| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061 |
- package strmatcher
- import (
- "sort"
- "strings"
- )
- // SubstrMatcherGroup is implementation of MatcherGroup,
- // It is simply implmeneted to comply with the priority specification of Substr matchers.
- type SubstrMatcherGroup struct {
- patterns []string
- values []uint32
- }
- // AddSubstrMatcher implements MatcherGroupForSubstr.AddSubstrMatcher.
- func (g *SubstrMatcherGroup) AddSubstrMatcher(matcher SubstrMatcher, value uint32) {
- g.patterns = append(g.patterns, matcher.Pattern())
- g.values = append(g.values, value)
- }
- // Match implements MatcherGroup.Match.
- func (g *SubstrMatcherGroup) Match(input string) []uint32 {
- var result []uint32
- for i, pattern := range g.patterns {
- for j := strings.LastIndex(input, pattern); j != -1; j = strings.LastIndex(input[:j], pattern) {
- result = append(result, uint32(j)<<16|uint32(i)&0xffff) // uint32: position (higher 16 bit) | patternIdx (lower 16 bit)
- }
- }
- // sort.Slice will trigger allocation no matter what input is. See https://github.com/golang/go/issues/17332
- // We optimize the sorting by length to prevent memory allocation as possible.
- switch len(result) {
- case 0:
- return nil
- case 1:
- // No need to sort
- case 2:
- // Do a simple swap if unsorted
- if result[0] > result[1] {
- result[0], result[1] = result[1], result[0]
- }
- default:
- // Sort the match results in dictionary order, so that:
- // 1. Pattern matched at smaller position (meaning matched further) takes precedence.
- // 2. When patterns matched at same position, pattern with smaller index (meaning inserted early) takes precedence.
- sort.Slice(result, func(i, j int) bool { return result[i] < result[j] })
- }
- for i, entry := range result {
- result[i] = g.values[entry&0xffff] // Get pattern value from its index (the lower 16 bit)
- }
- return result
- }
- // MatchAny implements MatcherGroup.MatchAny.
- func (g *SubstrMatcherGroup) MatchAny(input string) bool {
- for _, pattern := range g.patterns {
- if strings.Contains(input, pattern) {
- return true
- }
- }
- return false
- }
|