Files
redis-go/lib/wildcard/wildcard.go
2021-08-13 13:56:53 +08:00

132 lines
2.6 KiB
Go

package wildcard
const (
normal = iota
all // *
any // ?
setSymbol // []
rangSymbol // [a-b]
negSymbol // [^a]
)
type item struct {
character byte
set map[byte]bool
typeCode int
}
func (i *item) contains(c byte) bool {
if i.typeCode == setSymbol {
_, ok := i.set[c]
return ok
} else if i.typeCode == rangSymbol {
if _, ok := i.set[c]; ok {
return true
}
var (
min uint8 = 255
max uint8 = 0
)
for k, _ := range i.set {
if min > k {
min = k
}
if max < k {
max = k
}
}
return c >= min && c <= max
} else {
_, ok := i.set[c]
return !ok
}
}
// Pattern represents a wildcard pattern
type Pattern struct {
items []*item
}
// CompilePattern convert wildcard string to Pattern
func CompilePattern(src string) *Pattern {
items := make([]*item, 0)
escape := false
inSet := false
var set map[byte]bool
for _, v := range src {
c := byte(v)
if escape {
items = append(items, &item{typeCode: normal, character: c})
escape = false
} else if c == '*' {
items = append(items, &item{typeCode: all})
} else if c == '?' {
items = append(items, &item{typeCode: any})
} else if c == '\\' {
escape = true
} else if c == '[' {
if !inSet {
inSet = true
set = make(map[byte]bool)
} else {
set[c] = true
}
} else if c == ']' {
if inSet {
inSet = false
typeCode := setSymbol
if _, ok := set['-']; ok {
typeCode = rangSymbol
delete(set, '-')
}
if _, ok := set['^']; ok {
typeCode = negSymbol
delete(set, '^')
}
items = append(items, &item{typeCode: typeCode, set: set})
} else {
items = append(items, &item{typeCode: normal, character: c})
}
} else {
if inSet {
set[c] = true
} else {
items = append(items, &item{typeCode: normal, character: c})
}
}
}
return &Pattern{
items: items,
}
}
// IsMatch returns whether the given string matches pattern
func (p *Pattern) IsMatch(s string) bool {
if len(p.items) == 0 {
return len(s) == 0
}
m := len(s)
n := len(p.items)
table := make([][]bool, m+1)
for i := 0; i < m+1; i++ {
table[i] = make([]bool, n+1)
}
table[0][0] = true
for j := 1; j < n+1; j++ {
table[0][j] = table[0][j-1] && p.items[j-1].typeCode == all
}
for i := 1; i < m+1; i++ {
for j := 1; j < n+1; j++ {
if p.items[j-1].typeCode == all {
table[i][j] = table[i-1][j] || table[i][j-1]
} else {
table[i][j] = table[i-1][j-1] &&
(p.items[j-1].typeCode == any ||
(p.items[j-1].typeCode == normal && uint8(s[i-1]) == p.items[j-1].character) ||
(p.items[j-1].typeCode >= setSymbol && p.items[j-1].contains(s[i-1])))
}
}
}
return table[m][n]
}