You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

string.go 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. package substring
  2. import (
  3. "regexp"
  4. "strings"
  5. "github.com/toqueteos/trie"
  6. )
  7. type StringsMatcher interface {
  8. Match(s string) bool
  9. MatchIndex(s string) int
  10. }
  11. // regexp
  12. type regexpString struct{ re *regexp.Regexp }
  13. func Regexp(pat string) *regexpString { return &regexpString{regexp.MustCompile(pat)} }
  14. func (m *regexpString) Match(s string) bool { return m.re.MatchString(s) }
  15. func (m *regexpString) MatchIndex(s string) int {
  16. found := m.re.FindStringIndex(s)
  17. if found != nil {
  18. return found[1]
  19. }
  20. return -1
  21. }
  22. // exact
  23. type exactString struct{ pat string }
  24. func Exact(pat string) *exactString { return &exactString{pat} }
  25. func (m *exactString) Match(s string) bool { return m.pat == s }
  26. func (m *exactString) MatchIndex(s string) int {
  27. if m.pat == s {
  28. return len(s)
  29. }
  30. return -1
  31. }
  32. // any, search `s` in `.Match(pat)`
  33. type anyString struct{ pat string }
  34. func Any(pat string) *anyString { return &anyString{pat} }
  35. func (m *anyString) Match(s string) bool {
  36. return strings.Index(m.pat, s) >= 0
  37. }
  38. func (m *anyString) MatchIndex(s string) int {
  39. if idx := strings.Index(m.pat, s); idx >= 0 {
  40. return idx + len(s)
  41. }
  42. return -1
  43. }
  44. // has, search `pat` in `.Match(s)`
  45. type hasString struct{ pat string }
  46. func Has(pat string) *hasString { return &hasString{pat} }
  47. func (m *hasString) Match(s string) bool {
  48. return strings.Index(s, m.pat) >= 0
  49. }
  50. func (m *hasString) MatchIndex(s string) int {
  51. if idx := strings.Index(s, m.pat); idx >= 0 {
  52. return idx + len(m.pat)
  53. }
  54. return -1
  55. }
  56. // prefix
  57. type prefixString struct{ pat string }
  58. func Prefix(pat string) *prefixString { return &prefixString{pat} }
  59. func (m *prefixString) Match(s string) bool { return strings.HasPrefix(s, m.pat) }
  60. func (m *prefixString) MatchIndex(s string) int {
  61. if strings.HasPrefix(s, m.pat) {
  62. return len(m.pat)
  63. }
  64. return -1
  65. }
  66. // prefixes
  67. type prefixesString struct{ t *trie.Trie }
  68. func Prefixes(pats ...string) *prefixesString {
  69. t := trie.New()
  70. for _, pat := range pats {
  71. t.Insert([]byte(pat))
  72. }
  73. return &prefixesString{t}
  74. }
  75. func (m *prefixesString) Match(s string) bool { return m.t.PrefixIndex([]byte(s)) >= 0 }
  76. func (m *prefixesString) MatchIndex(s string) int {
  77. if idx := m.t.PrefixIndex([]byte(s)); idx >= 0 {
  78. return idx
  79. }
  80. return -1
  81. }
  82. // suffix
  83. type suffixString struct{ pat string }
  84. func Suffix(pat string) *suffixString { return &suffixString{pat} }
  85. func (m *suffixString) Match(s string) bool { return strings.HasSuffix(s, m.pat) }
  86. func (m *suffixString) MatchIndex(s string) int {
  87. if strings.HasSuffix(s, m.pat) {
  88. return len(m.pat)
  89. }
  90. return -1
  91. }
  92. // suffixes
  93. type suffixesString struct{ t *trie.Trie }
  94. func Suffixes(pats ...string) *suffixesString {
  95. t := trie.New()
  96. for _, pat := range pats {
  97. t.Insert(reverse([]byte(pat)))
  98. }
  99. return &suffixesString{t}
  100. }
  101. func (m *suffixesString) Match(s string) bool {
  102. return m.t.PrefixIndex(reverse([]byte(s))) >= 0
  103. }
  104. func (m *suffixesString) MatchIndex(s string) int {
  105. if idx := m.t.PrefixIndex(reverse([]byte(s))); idx >= 0 {
  106. return idx
  107. }
  108. return -1
  109. }
  110. // after
  111. type afterString struct {
  112. first string
  113. matcher StringsMatcher
  114. }
  115. func After(first string, m StringsMatcher) *afterString {
  116. return &afterString{first, m}
  117. }
  118. func (a *afterString) Match(s string) bool {
  119. if idx := strings.Index(s, a.first); idx >= 0 {
  120. return a.matcher.Match(s[idx+len(a.first):])
  121. }
  122. return false
  123. }
  124. func (a *afterString) MatchIndex(s string) int {
  125. if idx := strings.Index(s, a.first); idx >= 0 {
  126. return idx + a.matcher.MatchIndex(s[idx+len(a.first):])
  127. }
  128. return -1
  129. }
  130. // and, returns true iff all matchers return true
  131. type andString struct{ matchers []StringsMatcher }
  132. func And(m ...StringsMatcher) *andString { return &andString{m} }
  133. func (a *andString) Match(s string) bool {
  134. for _, m := range a.matchers {
  135. if !m.Match(s) {
  136. return false
  137. }
  138. }
  139. return true
  140. }
  141. func (a *andString) MatchIndex(s string) int {
  142. longest := 0
  143. for _, m := range a.matchers {
  144. if idx := m.MatchIndex(s); idx < 0 {
  145. return -1
  146. } else if idx > longest {
  147. longest = idx
  148. }
  149. }
  150. return longest
  151. }
  152. // or, returns true iff any matcher returns true
  153. type orString struct{ matchers []StringsMatcher }
  154. func Or(m ...StringsMatcher) *orString { return &orString{m} }
  155. func (o *orString) Match(s string) bool {
  156. for _, m := range o.matchers {
  157. if m.Match(s) {
  158. return true
  159. }
  160. }
  161. return false
  162. }
  163. func (o *orString) MatchIndex(s string) int {
  164. for _, m := range o.matchers {
  165. if idx := m.MatchIndex(s); idx >= 0 {
  166. return idx
  167. }
  168. }
  169. return -1
  170. }
  171. type suffixGroupString struct {
  172. suffix StringsMatcher
  173. matchers []StringsMatcher
  174. }
  175. func SuffixGroup(s string, m ...StringsMatcher) *suffixGroupString {
  176. return &suffixGroupString{Suffix(s), m}
  177. }
  178. func (sg *suffixGroupString) Match(s string) bool {
  179. if sg.suffix.Match(s) {
  180. return Or(sg.matchers...).Match(s)
  181. }
  182. return false
  183. }
  184. func (sg *suffixGroupString) MatchIndex(s string) int {
  185. if sg.suffix.MatchIndex(s) >= 0 {
  186. return Or(sg.matchers...).MatchIndex(s)
  187. }
  188. return -1
  189. }