matchers.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. package strmatcher
  2. import (
  3. "errors"
  4. "regexp"
  5. "strings"
  6. )
  7. // FullMatcher is an implementation of Matcher.
  8. type FullMatcher string
  9. func (FullMatcher) Type() Type {
  10. return Full
  11. }
  12. func (m FullMatcher) Pattern() string {
  13. return string(m)
  14. }
  15. func (m FullMatcher) String() string {
  16. return "full:" + m.Pattern()
  17. }
  18. func (m FullMatcher) Match(s string) bool {
  19. return string(m) == s
  20. }
  21. // DomainMatcher is an implementation of Matcher.
  22. type DomainMatcher string
  23. func (DomainMatcher) Type() Type {
  24. return Domain
  25. }
  26. func (m DomainMatcher) Pattern() string {
  27. return string(m)
  28. }
  29. func (m DomainMatcher) String() string {
  30. return "domain:" + m.Pattern()
  31. }
  32. func (m DomainMatcher) Match(s string) bool {
  33. pattern := m.Pattern()
  34. if !strings.HasSuffix(s, pattern) {
  35. return false
  36. }
  37. return len(s) == len(pattern) || s[len(s)-len(pattern)-1] == '.'
  38. }
  39. // SubstrMatcher is an implementation of Matcher.
  40. type SubstrMatcher string
  41. func (SubstrMatcher) Type() Type {
  42. return Substr
  43. }
  44. func (m SubstrMatcher) Pattern() string {
  45. return string(m)
  46. }
  47. func (m SubstrMatcher) String() string {
  48. return "keyword:" + m.Pattern()
  49. }
  50. func (m SubstrMatcher) Match(s string) bool {
  51. return strings.Contains(s, m.Pattern())
  52. }
  53. // RegexMatcher is an implementation of Matcher.
  54. type RegexMatcher struct {
  55. pattern *regexp.Regexp
  56. }
  57. func (*RegexMatcher) Type() Type {
  58. return Regex
  59. }
  60. func (m *RegexMatcher) Pattern() string {
  61. return m.pattern.String()
  62. }
  63. func (m *RegexMatcher) String() string {
  64. return "regexp:" + m.Pattern()
  65. }
  66. func (m *RegexMatcher) Match(s string) bool {
  67. return m.pattern.MatchString(s)
  68. }
  69. // New creates a new Matcher based on the given pattern.
  70. func (t Type) New(pattern string) (Matcher, error) {
  71. switch t {
  72. case Full:
  73. return FullMatcher(pattern), nil
  74. case Substr:
  75. return SubstrMatcher(pattern), nil
  76. case Domain:
  77. return DomainMatcher(pattern), nil
  78. case Regex: // 1. regex matching is case-sensitive
  79. regex, err := regexp.Compile(pattern)
  80. if err != nil {
  81. return nil, err
  82. }
  83. return &RegexMatcher{pattern: regex}, nil
  84. default:
  85. panic("Unknown type")
  86. }
  87. }
  88. // MatcherGroupForAll is an interface indicating a MatcherGroup could accept all types of matchers.
  89. type MatcherGroupForAll interface {
  90. AddMatcher(matcher Matcher, value uint32)
  91. }
  92. // MatcherGroupForFull is an interface indicating a MatcherGroup could accept FullMatchers.
  93. type MatcherGroupForFull interface {
  94. AddFullMatcher(matcher FullMatcher, value uint32)
  95. }
  96. // MatcherGroupForDomain is an interface indicating a MatcherGroup could accept DomainMatchers.
  97. type MatcherGroupForDomain interface {
  98. AddDomainMatcher(matcher DomainMatcher, value uint32)
  99. }
  100. // MatcherGroupForSubstr is an interface indicating a MatcherGroup could accept SubstrMatchers.
  101. type MatcherGroupForSubstr interface {
  102. AddSubstrMatcher(matcher SubstrMatcher, value uint32)
  103. }
  104. // MatcherGroupForRegex is an interface indicating a MatcherGroup could accept RegexMatchers.
  105. type MatcherGroupForRegex interface {
  106. AddRegexMatcher(matcher *RegexMatcher, value uint32)
  107. }
  108. // AddMatcherToGroup is a helper function to try to add a Matcher to any kind of MatcherGroup.
  109. // It returns error if the MatcherGroup does not accept the provided Matcher's type.
  110. // This function is provided to help writing code to test a MatcherGroup.
  111. func AddMatcherToGroup(g MatcherGroup, matcher Matcher, value uint32) error {
  112. if g, ok := g.(MatcherGroupForAll); ok {
  113. g.AddMatcher(matcher, value)
  114. return nil
  115. }
  116. switch matcher := matcher.(type) {
  117. case FullMatcher:
  118. if g, ok := g.(MatcherGroupForFull); ok {
  119. g.AddFullMatcher(matcher, value)
  120. return nil
  121. }
  122. case DomainMatcher:
  123. if g, ok := g.(MatcherGroupForDomain); ok {
  124. g.AddDomainMatcher(matcher, value)
  125. return nil
  126. }
  127. case SubstrMatcher:
  128. if g, ok := g.(MatcherGroupForSubstr); ok {
  129. g.AddSubstrMatcher(matcher, value)
  130. return nil
  131. }
  132. case *RegexMatcher:
  133. if g, ok := g.(MatcherGroupForRegex); ok {
  134. g.AddRegexMatcher(matcher, value)
  135. return nil
  136. }
  137. }
  138. return errors.New("cannot add matcher to matcher group")
  139. }