master
go 60 lines 1.35 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package matcher
4
5 import "regexp"
6
7 // NewRegExpMatcher create new matcher with RegExp format
8 func NewRegExpMatcher(expr string) (Matcher, error) {
9 switch expr {
10 case "", "^", "$":
11 return TRUE(), nil
12 case "^$", "$^":
13 return NewStringMatcher("", true, true)
14 }
15 size := len(expr)
16 chars := []rune(expr)
17 var startWith, endWith bool
18 startIdx := 0
19 endIdx := size - 1
20 if chars[startIdx] == '^' {
21 startWith = true
22 startIdx = 1
23 }
24 if chars[endIdx] == '$' {
25 endWith = true
26 endIdx--
27 }
28
29 unescapedExpr := make([]rune, 0, endIdx-startIdx+1)
30 for i := startIdx; i <= endIdx; i++ {
31 ch := chars[i]
32 if ch == '\\' {
33 if i == endIdx { // end with '\' => invalid format
34 return regexp.Compile(expr)
35 }
36 nextCh := chars[i+1]
37 if !isRegExpMeta(nextCh) { // '\' + mon-meta char => special meaning
38 return regexp.Compile(expr)
39 }
40 unescapedExpr = append(unescapedExpr, nextCh)
41 i++
42 } else if isRegExpMeta(ch) {
43 return regexp.Compile(expr)
44 } else {
45 unescapedExpr = append(unescapedExpr, ch)
46 }
47 }
48
49 return NewStringMatcher(string(unescapedExpr), startWith, endWith)
50 }
51
52 // isRegExpMeta reports whether byte b needs to be escaped by QuoteMeta.
53 func isRegExpMeta(b rune) bool {
54 switch b {
55 case '\\', '.', '+', '*', '?', '(', ')', '|', '[', ']', '{', '}', '^', '$':
56 return true
57 default:
58 return false
59 }
60 }