package filepath
import (
"errors"
"os"
"strings"
"unicode/utf8"
)
var ErrBadPattern = errors.New("syntax error in pattern")
func Match(pattern, name string) (matched bool, err error) {
Pattern:
for len(pattern) > 0 {
var startWithStar bool
var chunk string
startWithStar, chunk, pattern = scanChunk(pattern)
if startWithStar && chunk == "" {
return !strings.Contains(name, string(os.PathSeparator)), nil
}
if !startWithStar {
restName, matched, err := matchChunk(chunk, name)
if err != nil {
return false, err
}
if !matched {
return false, nil
}
name = restName
} else {
for i := 0; i < len(name); i++ {
if i-1 >= 0 && os.IsPathSeparator(name[i-1]) {
break
}
restName, ok, err := matchChunk(chunk, name[i:])
if ok {
if len(pattern) == 0 && len(restName) > 0 {
continue
}
name = restName
continue Pattern
}
if err != nil {
return false, nil
}
}
return false, nil
}
}
return len(name) == 0, nil
}
func scanChunk(pattern string) (startWithStar bool, chunk string, rest string) {
for len(pattern) > 0 && pattern[0] == '*' {
pattern = pattern[1:]
startWithStar = true
}
inrange := false
var i int
Scan:
for i = 0; i < len(pattern); i++ {
switch pattern[i] {
case '\\':
if i+1 < len(pattern) {
i++
}
case '[':
inrange = true
case ']':
inrange = false
case '*':
if !inrange {
break Scan
}
}
}
return startWithStar, pattern[:i], pattern[i:]
}
func matchChunk(chunk, s string) (rest string, matched bool, err error) {
for len(chunk) > 0 {
if len(s) == 0 {
return
}
switch chunk[0] {
case '[':
r, n := utf8.DecodeRuneInString(s)
s = s[n:]
chunk = chunk[1:]
if len(chunk) == 0 {
err = ErrBadPattern
return
}
negated := chunk[0] == '^'
if negated {
chunk = chunk[1:]
}
match := false
nrange := 0
for {
if len(chunk) > 0 && chunk[0] == ']' && nrange > 0 {
chunk = chunk[1:]
break
}
var lo, hi rune
if lo, chunk, err = getEcs(chunk); err != nil {
return
}
hi = lo
if chunk[0] == '-' {
if hi, chunk, err = getEcs(chunk[1:]); err != nil {
return
}
}
if lo <= r && r <= hi {
match = true
}
nrange++
}
if match == negated {
return
}
case '?':
if s[0] == os.PathSeparator {
return
}
_, n := utf8.DecodeRuneInString(s)
s = s[n:]
chunk = chunk[1:]
case '\\':
chunk = chunk[1:]
if len(chunk) == 0 {
err = ErrBadPattern
return
}
fallthrough
default:
if chunk[0] != s[0] {
return
}
s = s[1:]
chunk = chunk[1:]
}
}
return s, true, nil
}
func getEcs(chunk string) (r rune, nchunk string, err error) {
if len(chunk) == 0 || chunk[0] == '-' || chunk[0] == ']' {
err = ErrBadPattern
return
}
if chunk[0] == '\\' {
chunk = chunk[1:]
if len(chunk) == 0 {
err = ErrBadPattern
return
}
}
r, n := utf8.DecodeRuneInString(chunk)
if r == utf8.RuneError && n == 1 {
err = ErrBadPattern
}
nchunk = chunk[n:]
if len(nchunk) == 0 {
err = ErrBadPattern
}
return
}
样例源码:github.com/morganxf/ex…