diff --git a/glob.go b/glob.go index 0853e87..b534aec 100644 --- a/glob.go +++ b/glob.go @@ -13,40 +13,28 @@ const ( var Chars = []string{Any, SuperAny, SingleAny} -type Matcher interface { +type Glob interface { Match(string) bool } -func firstIndexOfChars(p string, any []string) (min int, c string) { - l := len(p) - min = l - weight := 0 +func New(pattern string, d ...string) Glob { + chunks := parse(pattern, nil, strings.Join(d, "")) - 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 len(chunks) == 1 { + return chunks[0] } - if min == l { - return -1, "" - } - - return + return &composite{chunks} } -func parse(p string, m []Matcher, d []string) ([]Matcher, error) { +func parse(p string, m []Glob, d string) []Glob { if len(p) == 0 { - return m, nil + return m } i, c := firstIndexOfChars(p, Chars) if i == -1 { - return append(m, raw{p}), nil + return append(m, raw{p}) } if i > 0 { @@ -65,19 +53,6 @@ func parse(p string, m []Matcher, d []string) ([]Matcher, error) { return parse(p[i+len(c):], m, d) } -func New(pattern string, d ...string) (Matcher, error) { - chunks, err := parse(pattern, nil, d) - if err != nil { - return nil, err - } - - if len(chunks) == 1 { - return chunks[0], nil - } - - return &composite{chunks}, nil -} - type raw struct { s string } @@ -89,39 +64,36 @@ func (self raw) String() string { } type multiple struct { - delimiters []string + delimiters string } + func (self multiple) Match(s string) bool { - i, _ := firstIndexOfChars(s, self.delimiters) - return i == -1 + return strings.IndexAny(s, self.delimiters) == -1 } + func (self multiple) String() string { return fmt.Sprintf("[multiple:%s]", self.delimiters) } type single struct { - delimiters []string + delimiters string } + func (self single) Match(s string) bool { - if len(s) != 1 { - return false - } - - i, _ := firstIndexOfChars(s, self.delimiters) - - return i == -1 + return len(s) == 1 && strings.IndexAny(s, self.delimiters) == -1 } + func (self single) String() string { return fmt.Sprintf("[single:%s]", self.delimiters) } type composite struct { - chunks []Matcher + chunks []Glob } func (self composite) Match(m string) bool { - var prev Matcher + var prev Glob for _, c := range self.chunks { if str, ok := c.(raw); ok { @@ -153,3 +125,25 @@ func (self composite) Match(m string) bool { return len(m) == 0 } + +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 +} \ No newline at end of file diff --git a/glob_test.go b/glob_test.go index f6ee7b8..b0d72a0 100644 --- a/glob_test.go +++ b/glob_test.go @@ -56,10 +56,12 @@ func TestGlob(t *testing.T) { glob(true, "a.?.c", "a.b.c", "."), glob(true, "a.?.?", "a.b.c", "."), glob(true, "?at", "cat"), + glob(true, "?at", "fat"), glob(true, "*", "abc"), glob(true, "**", "a.b.c", "."), glob(false, "?at", "at"), + glob(false, "?at", "fat", "f"), glob(false, "a.*", "a.b.c", "."), glob(false, "a.?.c", "a.bb.c", "."), glob(false, "*", "a.b.c", "."), @@ -74,11 +76,7 @@ func TestGlob(t *testing.T) { glob(false, "*is", "this is a test"), glob(false, "*no*", "this is a test"), }{ - g, err := New(test.pattern, test.delimiters...) - if err != nil { - t.Error(err) - continue - } + g := New(test.pattern, test.delimiters...) result := g.Match(test.match) if result != test.should { @@ -91,14 +89,14 @@ func TestGlob(t *testing.T) { const Pattern = "*cat*eyes*" const ExpPattern = ".*cat.*eyes.*" const String = "my cat has very bright eyes" +//const Pattern = "*.google.com" +//const ExpPattern = ".*google\\.com" +//const String = "mail.google.com" func BenchmarkGobwas(b *testing.B) { - for i := 0; i < b.N; i++ { - m, err := New(Pattern) - if err != nil { - b.Fatal(err) - } + m := New(Pattern) + for i := 0; i < b.N; i++ { _ = m.Match(String) } } diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..df10b39 --- /dev/null +++ b/readme.md @@ -0,0 +1,50 @@ +# glob.[go](https://golang.org) + +Simple globbing library. + +## Install + +```shell + go get github.com/gobwas/glob +``` + +## Example + +```go + +package main + +import "github.com/gobwas/glob" + +func main() { + var g glob.Glob + + // create simple glob + g = glob.New("*.github.com") + g.Match("api.github.com") // true + + // create new glob with set of delimiters as ["."] + g = glob.New("api.*.com", ".") + g.Match("api.github.com") // true + g.Match("api.gi.hub.com") // false + + // create new glob with set of delimiters as ["."] + // but now with super wildcard + g = glob.New("api.**.com", ".") + g.Match("api.github.com") // true + g.Match("api.gi.hub.com") // true + + // create glob with single symbol wildcard + g = glob.New("?at") + g.Match("cat") // true + g.Match("fat") // true + g.Match("at") // false + + // create glob with single symbol wildcard and delimiters ["f"] + g = glob.New("?at", "f") + g.Match("cat") // true + g.Match("fat") // false + g.Match("at") // false +} + +``` \ No newline at end of file