-
Notifications
You must be signed in to change notification settings - Fork 13
/
matcher.go
158 lines (138 loc) · 4.48 KB
/
matcher.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package marker
import (
"fmt"
"regexp"
"sort"
"strings"
)
// MatcherFunc returns a Match which contains information about found patterns
type MatcherFunc func(string) Match
// Match contains information about found patterns by MatcherFunc
type Match struct {
Template string
Patterns []string
}
// MatchAll creates a MatcherFunc that matches all patterns in given string
func MatchAll(pattern string) MatcherFunc {
return func(str string) Match {
count := strings.Count(str, pattern)
return Match{
Template: strings.ReplaceAll(str, pattern, "%s"),
Patterns: fillSlice(make([]string, count), pattern),
}
}
}
// MatchN creates a MatcherFunc that matches first n patterns in given string
func MatchN(pattern string, n int) MatcherFunc {
return func(str string) Match {
count := min(n, strings.Count(str, pattern))
return Match{
Template: strings.Replace(str, pattern, "%s", n),
Patterns: fillSlice(make([]string, count), pattern),
}
}
}
// MatchMultiple creates a MatcherFunc that matches all string patterns from given slice in given string
func MatchMultiple(patternsToMatch []string) MatcherFunc {
return func(str string) Match {
patternMatchIndexes := findPatternMatchIndexes(str, patternsToMatch)
patterns := getPatternsInOrder(patternMatchIndexes)
return Match{
Template: replaceMultiple(str, patternsToMatch, "%s"),
Patterns: patterns,
}
}
}
// MatchRegexp creates a MatcherFunc that matches given regexp in given string
func MatchRegexp(r *regexp.Regexp) MatcherFunc {
return func(str string) Match {
return Match{
Template: r.ReplaceAllString(str, "%s"),
Patterns: r.FindAllString(str, -1),
}
}
}
// MatchTimestamp creates a MatcherFunc that matches given time layout pattern in given string
func MatchTimestamp(layout string) MatcherFunc {
return func(str string) Match {
r := timestampLayoutRegexps[layout]
return MatchRegexp(r)(str)
}
}
// MatchSurrounded creates a MatcherFunc that matches the patterns surrounded by given opening and closure strings
func MatchSurrounded(opening string, closure string) MatcherFunc {
return func(str string) Match {
metaEscapedOpening := regexp.QuoteMeta(opening)
metaEscapedClosure := regexp.QuoteMeta(closure)
matchPattern := fmt.Sprintf("%s[^%s]*%s", metaEscapedOpening, metaEscapedOpening, metaEscapedClosure)
r, _ := regexp.Compile(matchPattern)
return MatchRegexp(r)(str)
}
}
// MatchBracketSurrounded is a helper utility for easy matching of bracket surrounded text
func MatchBracketSurrounded() MatcherFunc {
return MatchSurrounded("[", "]")
}
// MatchParensSurrounded is a helper utility for easy matching text surrounded in parentheses
func MatchParensSurrounded() MatcherFunc {
return MatchSurrounded("(", ")")
}
// MatchEmail creates a MatcherFunc that matches emails which meets the conditions of RFC5322 standard
func MatchEmail() MatcherFunc {
return func(str string) Match {
return MatchRegexp(EmailRegexp)(str)
}
}
var daysOfWeek = [14]string{"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday",
"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}
// MatchDaysOfWeek creates a MatcherFunc that matches days of the week in given string
func MatchDaysOfWeek() MatcherFunc {
return func(str string) Match {
return MatchMultiple(daysOfWeek[:])(str)
}
}
func findPatternMatchIndexes(str string, patternsToMatch []string) map[int]string {
patternMatchIndexes := make(map[int]string)
pattern := strings.Join(patternsToMatch , "|")
patternRegex := regexp.MustCompile(pattern)
indices := patternRegex.FindAllStringIndex(str, -1)
for _, v := range(indices) {
start, end := v[0], v[1]
patternMatchIndexes[start] = str[start:end]
}
return patternMatchIndexes
}
func getPatternsInOrder(patternMatchIndexes map[int]string) []string {
matchIndexes := getKeys(patternMatchIndexes)
sort.Ints(matchIndexes)
patterns := make([]string, 0, len(patternMatchIndexes))
for _, index := range matchIndexes {
patterns = append(patterns, patternMatchIndexes[index])
}
return patterns
}
func getKeys(m map[int]string) []int {
keys := make([]int, 0, len(m))
for key := range m {
keys = append(keys, key)
}
return keys
}
func replaceMultiple(str string, patterns []string, with string) string {
for _, patternToMatch := range patterns {
str = strings.ReplaceAll(str, patternToMatch, with)
}
return str
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func fillSlice(s []string, v string) []string {
for i := range s {
s[i] = v
}
return s
}