代码备份
Opened this issue · 0 comments
nailcui commented
redis keys匹配的golang实现
// Glob-style pattern matching.
func StringMatch(pattern, str string) bool {
if pattern == "*" {
return true
}
patternLen := len(pattern)
strLen := len(str)
for patternLen > 0 {
switch pattern[0] {
case '*':
for patternLen > 1 && pattern[1] == '*' {
pattern = pattern[1:]
patternLen--
}
if patternLen == 1 {
return true
}
for strLen > 0 {
if StringMatch(pattern[1:], str) {
return true
}
str = str[1:]
strLen--
}
return false
case '?':
if strLen == 0 {
return false
}
str = str[1:]
strLen--
case '[':
var not, match bool
var prePattern string
pattern = pattern[1:]
patternLen--
not = patternLen > 0 && pattern[0] == '^'
if not {
prePattern = pattern
pattern = pattern[1:]
patternLen--
}
match = false
for {
if patternLen > 0 && pattern[0] == '\\' {
pattern = pattern[1:]
patternLen--
match = pattern[0] == str[0]
} else if patternLen > 0 && pattern[0] == ']' {
break
} else if patternLen == 0 {
pattern = prePattern
patternLen = len(pattern)
break
} else if patternLen >= 3 && pattern[1] == '-' {
start := pattern[0]
end := pattern[2]
c := str[0]
if start > end {
start, end = end, start
}
pattern = pattern[2:]
patternLen-=2
if c >= start && c <= end {
match = true
}
} else if pattern[0] == str[0] {
match = true
}
prePattern = pattern
pattern = pattern[1:]
patternLen--
}
if not {
match = !match
}
if !match {
return false
}
str = str[1:]
strLen--
case '\\':
if patternLen >= 2 {
pattern = pattern[1:]
patternLen--
}
if string(pattern[0]) != string(str[0]) {
return false
}
str = str[1:]
strLen--
default:
if string(pattern[0]) != string(str[0]) {
return false
}
str = str[1:]
strLen--
}
pattern = pattern[1:]
patternLen--
if strLen == 0 {
for patternLen > 0 && pattern[0] == '*' {
pattern = pattern[1:]
patternLen--
}
break
}
}
if patternLen == 0 && strLen == 0 {
return true
}
return false
}
单元测试
func TestStringMatch(t *testing.T) {
assertions := assert.New(t)
tests := []struct {
pattern string
str string
want bool
}{
{"a**", "abcd", true},
{"a**b", "abcd", false},
{"abcd", "abcd", true},
{"*", "abcd", true},
{"\\a", "a", true},
{"a?c", "abc", true},
{"a?c", "abbc", false},
{"ab*", "ab", true},
{"ab*", "abcd", true},
{"ab*cd", "abcd", true},
{"ab*cd", "ab-cd", true},
{"ab*cd", "ab--cd", true},
{"ab[ef]", "abe", true},
{"ab[ef]", "abf", true},
{"ab[ef]", "abef", false},
{"[ef]cd", "ecd", true},
{"[ef]cd", "fcd", true},
{"[ef]cd", "efcd", false},
{"ab[ef]cd", "abecd", true},
{"ab[ef]cd", "abfcd", true},
{"ab[ef]cd", "abefcd", false},
{"ab[^e]cd", "abfcd", true},
{"ab[^e]cd", "abffcd", false},
{"ab[^ef]cd", "abfcd", false},
{"ab[^ef]cd", "abwcd", true},
{"ab[a-d]cd", "abacd", true},
{"ab[d-a]cd", "abacd", true},
{"ab[a-d]cd", "ababcd", false},
{"ab[a-d]cd", "abecd", false},
{"ab[a-d]cd", "abefcd", false},
{"ab[a-d]cd", "ababcd", false},
{"ab[", "ab[", false},
{"ab[a", "ab[a", false},
{"ab[[", "ab[", true},
{"ab[[a", "ab[", true},
{"ab[[ab", "ab[", true},
{"ab[[a", "ab[a", false},
}
for _, tt := range tests {
t.Run(tt.pattern, func(t *testing.T) {
assertions.Equal(tt.want, StringMatch(tt.pattern, tt.str),
fmt.Sprintf("TestStringMatch pattern: %s, str: %s", tt.pattern, tt.str))
})
}
}