testmatch.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. package main
  2. import (
  3. //"fmt"
  4. "path"
  5. "strings"
  6. "unicode/utf8"
  7. "regexp"
  8. )
  9. var ErrBadPattern = path.ErrBadPattern
  10. func main(){
  11. match, _ := ExpMatch("linux*","linux1")
  12. println(match)
  13. match, _ = regexp.MatchString("linux.*?","linux1")
  14. println("regexp ==>", match)
  15. match, _ = ExpMatch("linux?","linux1")
  16. println(match)
  17. match, _ = regexp.MatchString("linux.","linux1")
  18. println("regexp ==>", match)
  19. match, _ = ExpMatch("linux[1-2]","linux1")
  20. println(match)
  21. match, _ = regexp.MatchString("linux[1-2]","linux1")
  22. println("regexp ==>", match)
  23. match, _ = ExpMatch("linux[12]","linux1")
  24. println(match)
  25. match, _ = regexp.MatchString("linux[12]","linux1")
  26. println("regexp ==>", match)
  27. match, _ = ExpMatch("linux[^2345]","linux1")
  28. println(match)
  29. match, _ = regexp.MatchString("linux[^2345]","linux1")
  30. println("regexp ==>", match)
  31. println("----------------------")
  32. match, _ = ExpMatch("linux[^12345]","linux1")
  33. println(match)
  34. match, _ = regexp.MatchString("linux[^12345]","linux1")
  35. println("regexp ==>", match)
  36. match, _ = ExpMatch("linux*[^12345]","linux1")
  37. println(match)
  38. match, _ = regexp.MatchString("linux.*?[^12345]","linux1")
  39. println("regexp ==>", match)
  40. match, _ = ExpMatch("中文*","中文测试")
  41. println(match)
  42. match, _ = regexp.MatchString("中文*","中文测试")
  43. println("regexp ==>", match)
  44. match, _ = ExpMatch("中文??","中文测试")
  45. println(match)
  46. match, _ = regexp.MatchString("中文..","中文测试")
  47. println("regexp ==>", match)
  48. srp := strings.NewReplacer("?", ".", "*", ".*?")
  49. s := "linux*?"
  50. print( "replace ==>", srp.Replace(s) )
  51. }
  52. func ExpMatch(pattern, name string) (bool, error) {
  53. // check some base cases
  54. patternLen, nameLen := len(pattern), len(name)
  55. if patternLen == 0 && nameLen == 0 {
  56. return true, nil
  57. }
  58. if patternLen == 0 {
  59. return false, nil
  60. }
  61. if nameLen == 0 && pattern != "*" {
  62. return false, nil
  63. }
  64. // check for matches one rune at a time
  65. patIdx, nameIdx := 0, 0
  66. for patIdx < patternLen && nameIdx < nameLen {
  67. patRune, patAdj := utf8.DecodeRuneInString(pattern[patIdx:])
  68. nameRune, nameAdj := utf8.DecodeRuneInString(name[nameIdx:])
  69. if patRune == '\\' {
  70. // handle escaped runes
  71. patIdx += patAdj
  72. patRune, patAdj = utf8.DecodeRuneInString(pattern[patIdx:])
  73. if patRune == utf8.RuneError {
  74. return false, ErrBadPattern
  75. } else if patRune == nameRune {
  76. patIdx += patAdj
  77. nameIdx += nameAdj
  78. } else {
  79. return false, nil
  80. }
  81. } else if patRune == '*' {
  82. // handle stars
  83. if patIdx += patAdj; patIdx >= patternLen {
  84. // a star at the end of a pattern will always
  85. // match the rest of the path
  86. return true, nil
  87. }
  88. // check if we can make any matches
  89. for ; nameIdx < nameLen; nameIdx += nameAdj {
  90. if m, _ := ExpMatch(pattern[patIdx:], name[nameIdx:]); m {
  91. return true, nil
  92. }
  93. }
  94. return false, nil
  95. } else if patRune == '[' {
  96. // handle character sets
  97. patIdx += patAdj
  98. endClass := indexRuneWithEscaping(pattern[patIdx:], ']')
  99. if endClass == -1 {
  100. return false, ErrBadPattern
  101. }
  102. endClass += patIdx
  103. classRunes := []rune(pattern[patIdx:endClass])
  104. classRunesLen := len(classRunes)
  105. if classRunesLen > 0 {
  106. classIdx := 0
  107. matchClass := false
  108. if classRunes[0] == '^' {
  109. classIdx++
  110. }
  111. for classIdx < classRunesLen {
  112. low := classRunes[classIdx]
  113. if low == '-' {
  114. return false, ErrBadPattern
  115. }
  116. classIdx++
  117. if low == '\\' {
  118. if classIdx < classRunesLen {
  119. low = classRunes[classIdx]
  120. classIdx++
  121. } else {
  122. return false, ErrBadPattern
  123. }
  124. }
  125. high := low
  126. if classIdx < classRunesLen && classRunes[classIdx] == '-' {
  127. // we have a range of runes
  128. if classIdx++; classIdx >= classRunesLen {
  129. return false, ErrBadPattern
  130. }
  131. high = classRunes[classIdx]
  132. if high == '-' {
  133. return false, ErrBadPattern
  134. }
  135. classIdx++
  136. if high == '\\' {
  137. if classIdx < classRunesLen {
  138. high = classRunes[classIdx]
  139. classIdx++
  140. } else {
  141. return false, ErrBadPattern
  142. }
  143. }
  144. }
  145. if low <= nameRune && nameRune <= high {
  146. matchClass = true
  147. }
  148. }
  149. if matchClass == (classRunes[0] == '^') {
  150. return false, nil
  151. }
  152. } else {
  153. return false, ErrBadPattern
  154. }
  155. patIdx = endClass + 1
  156. nameIdx += nameAdj
  157. }else if patRune == '?' || patRune == nameRune {
  158. // handle single-rune wildcard
  159. patIdx += patAdj
  160. nameIdx += nameAdj
  161. } else {
  162. return false, nil
  163. }
  164. }
  165. if patIdx >= patternLen && nameIdx >= nameLen {
  166. return true, nil
  167. }
  168. if nameIdx >= nameLen && pattern[patIdx:] == "*" || pattern[patIdx:] == "**" {
  169. return true, nil
  170. }
  171. return false, nil
  172. }
  173. // Find the first index of a rune in a string,
  174. // ignoring any times the rune is escaped using "\".
  175. func indexRuneWithEscaping(s string, r rune) int {
  176. end := strings.IndexRune(s, r)
  177. if end == -1 {
  178. return -1
  179. }
  180. if end > 0 && s[end-1] == '\\' {
  181. start := end + utf8.RuneLen(r)
  182. end = indexRuneWithEscaping(s[start:], r)
  183. if end != -1 {
  184. end += start
  185. }
  186. }
  187. return end
  188. }