Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
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.
216 lines
4.9 KiB
216 lines
4.9 KiB
package substring |
|
|
|
import ( |
|
"regexp" |
|
"strings" |
|
|
|
"github.com/toqueteos/trie" |
|
) |
|
|
|
type StringsMatcher interface { |
|
Match(s string) bool |
|
MatchIndex(s string) int |
|
} |
|
|
|
// regexp |
|
type regexpString struct{ re *regexp.Regexp } |
|
|
|
func Regexp(pat string) *regexpString { return ®expString{regexp.MustCompile(pat)} } |
|
func (m *regexpString) Match(s string) bool { return m.re.MatchString(s) } |
|
func (m *regexpString) MatchIndex(s string) int { |
|
found := m.re.FindStringIndex(s) |
|
if found != nil { |
|
return found[1] |
|
} |
|
return -1 |
|
} |
|
|
|
// exact |
|
type exactString struct{ pat string } |
|
|
|
func Exact(pat string) *exactString { return &exactString{pat} } |
|
func (m *exactString) Match(s string) bool { return m.pat == s } |
|
func (m *exactString) MatchIndex(s string) int { |
|
if m.pat == s { |
|
return len(s) |
|
} |
|
return -1 |
|
} |
|
|
|
// any, search `s` in `.Match(pat)` |
|
type anyString struct{ pat string } |
|
|
|
func Any(pat string) *anyString { return &anyString{pat} } |
|
func (m *anyString) Match(s string) bool { |
|
return strings.Index(m.pat, s) >= 0 |
|
} |
|
func (m *anyString) MatchIndex(s string) int { |
|
if idx := strings.Index(m.pat, s); idx >= 0 { |
|
return idx + len(s) |
|
} |
|
return -1 |
|
} |
|
|
|
// has, search `pat` in `.Match(s)` |
|
type hasString struct{ pat string } |
|
|
|
func Has(pat string) *hasString { return &hasString{pat} } |
|
func (m *hasString) Match(s string) bool { |
|
return strings.Index(s, m.pat) >= 0 |
|
} |
|
func (m *hasString) MatchIndex(s string) int { |
|
if idx := strings.Index(s, m.pat); idx >= 0 { |
|
return idx + len(m.pat) |
|
} |
|
return -1 |
|
} |
|
|
|
// prefix |
|
type prefixString struct{ pat string } |
|
|
|
func Prefix(pat string) *prefixString { return &prefixString{pat} } |
|
func (m *prefixString) Match(s string) bool { return strings.HasPrefix(s, m.pat) } |
|
func (m *prefixString) MatchIndex(s string) int { |
|
if strings.HasPrefix(s, m.pat) { |
|
return len(m.pat) |
|
} |
|
return -1 |
|
} |
|
|
|
// prefixes |
|
type prefixesString struct{ t *trie.Trie } |
|
|
|
func Prefixes(pats ...string) *prefixesString { |
|
t := trie.New() |
|
for _, pat := range pats { |
|
t.Insert([]byte(pat)) |
|
} |
|
return &prefixesString{t} |
|
} |
|
func (m *prefixesString) Match(s string) bool { return m.t.PrefixIndex([]byte(s)) >= 0 } |
|
func (m *prefixesString) MatchIndex(s string) int { |
|
if idx := m.t.PrefixIndex([]byte(s)); idx >= 0 { |
|
return idx |
|
} |
|
return -1 |
|
} |
|
|
|
// suffix |
|
type suffixString struct{ pat string } |
|
|
|
func Suffix(pat string) *suffixString { return &suffixString{pat} } |
|
func (m *suffixString) Match(s string) bool { return strings.HasSuffix(s, m.pat) } |
|
func (m *suffixString) MatchIndex(s string) int { |
|
if strings.HasSuffix(s, m.pat) { |
|
return len(m.pat) |
|
} |
|
return -1 |
|
} |
|
|
|
// suffixes |
|
type suffixesString struct{ t *trie.Trie } |
|
|
|
func Suffixes(pats ...string) *suffixesString { |
|
t := trie.New() |
|
for _, pat := range pats { |
|
t.Insert(reverse([]byte(pat))) |
|
} |
|
return &suffixesString{t} |
|
} |
|
func (m *suffixesString) Match(s string) bool { |
|
return m.t.PrefixIndex(reverse([]byte(s))) >= 0 |
|
} |
|
func (m *suffixesString) MatchIndex(s string) int { |
|
if idx := m.t.PrefixIndex(reverse([]byte(s))); idx >= 0 { |
|
return idx |
|
} |
|
return -1 |
|
} |
|
|
|
// after |
|
type afterString struct { |
|
first string |
|
matcher StringsMatcher |
|
} |
|
|
|
func After(first string, m StringsMatcher) *afterString { |
|
return &afterString{first, m} |
|
} |
|
func (a *afterString) Match(s string) bool { |
|
if idx := strings.Index(s, a.first); idx >= 0 { |
|
return a.matcher.Match(s[idx+len(a.first):]) |
|
} |
|
return false |
|
} |
|
func (a *afterString) MatchIndex(s string) int { |
|
if idx := strings.Index(s, a.first); idx >= 0 { |
|
return idx + a.matcher.MatchIndex(s[idx+len(a.first):]) |
|
} |
|
return -1 |
|
} |
|
|
|
// and, returns true iff all matchers return true |
|
type andString struct{ matchers []StringsMatcher } |
|
|
|
func And(m ...StringsMatcher) *andString { return &andString{m} } |
|
func (a *andString) Match(s string) bool { |
|
for _, m := range a.matchers { |
|
if !m.Match(s) { |
|
return false |
|
} |
|
} |
|
return true |
|
} |
|
func (a *andString) MatchIndex(s string) int { |
|
longest := 0 |
|
for _, m := range a.matchers { |
|
if idx := m.MatchIndex(s); idx < 0 { |
|
return -1 |
|
} else if idx > longest { |
|
longest = idx |
|
} |
|
} |
|
return longest |
|
} |
|
|
|
// or, returns true iff any matcher returns true |
|
type orString struct{ matchers []StringsMatcher } |
|
|
|
func Or(m ...StringsMatcher) *orString { return &orString{m} } |
|
func (o *orString) Match(s string) bool { |
|
for _, m := range o.matchers { |
|
if m.Match(s) { |
|
return true |
|
} |
|
} |
|
return false |
|
} |
|
func (o *orString) MatchIndex(s string) int { |
|
for _, m := range o.matchers { |
|
if idx := m.MatchIndex(s); idx >= 0 { |
|
return idx |
|
} |
|
} |
|
return -1 |
|
} |
|
|
|
type suffixGroupString struct { |
|
suffix StringsMatcher |
|
matchers []StringsMatcher |
|
} |
|
|
|
func SuffixGroup(s string, m ...StringsMatcher) *suffixGroupString { |
|
return &suffixGroupString{Suffix(s), m} |
|
} |
|
func (sg *suffixGroupString) Match(s string) bool { |
|
if sg.suffix.Match(s) { |
|
return Or(sg.matchers...).Match(s) |
|
} |
|
return false |
|
} |
|
func (sg *suffixGroupString) MatchIndex(s string) int { |
|
if sg.suffix.MatchIndex(s) >= 0 { |
|
return Or(sg.matchers...).MatchIndex(s) |
|
} |
|
return -1 |
|
}
|
|
|