glob/glob.go

151 lines
2.3 KiB
Go
Raw Normal View History

2015-11-30 17:58:20 +03:00
package glob
import (
"strings"
"fmt"
)
const (
2015-11-30 18:33:50 +03:00
any = "*"
superAny = "**"
singleAny = "?"
2015-11-30 17:58:20 +03:00
)
2015-11-30 18:33:50 +03:00
var chars = []string{any, superAny, singleAny}
2015-11-30 17:58:20 +03:00
2015-11-30 18:33:50 +03:00
// Glob represents compiled glob pattern.
2015-11-30 18:24:20 +03:00
type Glob interface {
2015-11-30 17:58:20 +03:00
Match(string) bool
}
2015-11-30 18:33:50 +03:00
// New creates Glob for given pattern and uses other given (if any) strings as delimiters.
2015-11-30 18:24:20 +03:00
func New(pattern string, d ...string) Glob {
chunks := parse(pattern, nil, strings.Join(d, ""))
2015-11-30 17:58:20 +03:00
2015-11-30 18:24:20 +03:00
if len(chunks) == 1 {
return chunks[0]
2015-11-30 17:58:20 +03:00
}
2015-11-30 18:24:20 +03:00
return &composite{chunks}
2015-11-30 17:58:20 +03:00
}
2015-11-30 18:24:20 +03:00
func parse(p string, m []Glob, d string) []Glob {
2015-11-30 17:58:20 +03:00
if len(p) == 0 {
2015-11-30 18:24:20 +03:00
return m
2015-11-30 17:58:20 +03:00
}
2015-11-30 18:33:50 +03:00
i, c := firstIndexOfChars(p, chars)
2015-11-30 17:58:20 +03:00
if i == -1 {
2015-11-30 18:24:20 +03:00
return append(m, raw{p})
2015-11-30 17:58:20 +03:00
}
if i > 0 {
m = append(m, raw{p[0:i]})
}
switch c {
2015-11-30 18:33:50 +03:00
case superAny:
2015-11-30 17:58:20 +03:00
m = append(m, multiple{})
2015-11-30 18:33:50 +03:00
case any:
2015-11-30 17:58:20 +03:00
m = append(m, multiple{d})
2015-11-30 18:33:50 +03:00
case singleAny:
2015-11-30 17:58:20 +03:00
m = append(m, single{d})
}
return parse(p[i+len(c):], m, d)
}
type raw struct {
s string
}
func (self raw) Match(s string) bool {
return self.s == s
}
func (self raw) String() string {
return fmt.Sprintf("[raw:%s]", self.s)
}
type multiple struct {
2015-11-30 18:24:20 +03:00
delimiters string
2015-11-30 17:58:20 +03:00
}
2015-11-30 18:24:20 +03:00
2015-11-30 17:58:20 +03:00
func (self multiple) Match(s string) bool {
2015-11-30 18:24:20 +03:00
return strings.IndexAny(s, self.delimiters) == -1
2015-11-30 17:58:20 +03:00
}
2015-11-30 18:24:20 +03:00
2015-11-30 17:58:20 +03:00
func (self multiple) String() string {
return fmt.Sprintf("[multiple:%s]", self.delimiters)
}
type single struct {
2015-11-30 18:24:20 +03:00
delimiters string
2015-11-30 17:58:20 +03:00
}
2015-11-30 18:24:20 +03:00
func (self single) Match(s string) bool {
return len(s) == 1 && strings.IndexAny(s, self.delimiters) == -1
2015-11-30 17:58:20 +03:00
}
2015-11-30 18:24:20 +03:00
2015-11-30 17:58:20 +03:00
func (self single) String() string {
return fmt.Sprintf("[single:%s]", self.delimiters)
}
type composite struct {
2015-11-30 18:24:20 +03:00
chunks []Glob
2015-11-30 17:58:20 +03:00
}
func (self composite) Match(m string) bool {
2015-11-30 18:24:20 +03:00
var prev Glob
2015-11-30 17:58:20 +03:00
for _, c := range self.chunks {
if str, ok := c.(raw); ok {
i := strings.Index(m, str.s)
if i == -1 {
return false
}
l := len(str.s)
if prev != nil {
if !prev.Match(m[:i]) {
return false
}
prev = nil
}
m = m[i+l:]
continue
}
prev = c
}
if prev != nil {
return prev.Match(m)
}
return len(m) == 0
}
2015-11-30 18:24:20 +03:00
func firstIndexOfChars(p string, any []string) (min int, c string) {
l := len(p)
min = l
weight := 0
for _, s := range any {
w := len(s)
i := strings.Index(p, s)
if i != -1 && i <= min && w > weight {
min = i
weight = w
c = s
}
}
if min == l {
return -1, ""
}
return
}