This commit is contained in:
s.kamardin 2015-12-24 19:00:41 +03:00
parent 5b4ed87b27
commit e39827db7b
3 changed files with 84 additions and 87 deletions

18
glob.go
View File

@ -2,8 +2,8 @@ package glob
import ( import (
"strings" "strings"
"errors"
"github.com/gobwas/glob/match" "github.com/gobwas/glob/match"
"fmt"
) )
const ( const (
@ -96,7 +96,7 @@ func parse(str string, sep string, st state) ([]token, error) {
case range_open: case range_open:
closed := indexByteNonEscaped(str, range_close, escape, 0) closed := indexByteNonEscaped(str, range_close, escape, 0)
if closed == -1 { if closed == -1 {
return nil, errors.New("invalid format") return nil, fmt.Errorf("'%s' should be closed with '%s'", string(range_open), string(range_close))
} }
r := str[i+1:closed] r := str[i+1:closed]
@ -135,6 +135,7 @@ func parseRange(def string) (match.Matcher, error) {
not bool not bool
esc bool esc bool
minus bool minus bool
minusIndex int
b []byte b []byte
) )
@ -152,26 +153,31 @@ func parseRange(def string) (match.Matcher, error) {
} }
case escape: case escape:
if i == len(def) - 1 { if i == len(def) - 1 {
return nil, errors.New("escape character without follower") return nil, fmt.Errorf("there should be any character after '%s'", string(escape))
} }
esc = true esc = true
case inside_range_minus: case inside_range_minus:
minus = true minus = true
minusIndex = len(b)
default: default:
b = append(b, c) b = append(b, c)
} }
} }
if len(b) == 0 {
return nil, fmt.Errorf("range could not be empty")
}
def = string(b) def = string(b)
if minus { if minus {
r := []rune(def) r := []rune(def)
if len(r) != 3 || r[1] != inside_range_minus { if len(r) != 2 || minusIndex != 1 {
return nil, errors.New("invalid range syntax") return nil, fmt.Errorf("invalid range syntax: '%s' should be between two characters", string(inside_range_minus))
} }
return &match.Between{r[0], r[2], not}, nil return &match.Between{r[0], r[1], not}, nil
} }
return &match.RangeList{def, not}, nil return &match.RangeList{def, not}, nil

View File

@ -1,11 +1,26 @@
package glob package glob
import ( import (
rGlob "github.com/ryanuber/go-glob"
"regexp"
"testing" "testing"
) )
const (
pattern_all = "[a-z][!a-x]*cat*[h][!b]*eyes*"
fixture_all = "my cat has very bright eyes"
pattern_plain = "google.com"
fixture_plain = "google.com"
pattern_multiple = "https://*.google.*"
fixture_multiple = "https://account.google.com"
pattern_prefix = "abc*"
pattern_suffix = "*def"
pattern_prefix_suffix = "ab*ef"
fixture_prefix_suffix = "abcdef"
)
type test struct { type test struct {
pattern, match string pattern, match string
should bool should bool
@ -16,7 +31,7 @@ func glob(s bool, p, m string, d ...string) test {
return test{p, m, s, d} return test{p, m, s, d}
} }
func TestIndexOfNonEscaped(t *testing.T) { func TestIndexByteNonEscaped(t *testing.T) {
for _, test := range []struct { for _, test := range []struct {
s string s string
n, e byte n, e byte
@ -46,6 +61,12 @@ func TestIndexOfNonEscaped(t *testing.T) {
'\\', '\\',
-1, -1,
}, },
{
"\\b",
'b',
'\\',
-1,
},
} { } {
i := indexByteNonEscaped(test.s, test.n, test.e, 0) i := indexByteNonEscaped(test.s, test.n, test.e, 0)
if i != test.i { if i != test.i {
@ -88,10 +109,18 @@ func TestGlob(t *testing.T) {
glob(false, "*is", "this is a test"), glob(false, "*is", "this is a test"),
glob(false, "*no*", "this is a test"), glob(false, "*no*", "this is a test"),
glob(true, "[!a]*", "this is a test"),
glob(true, pattern_all, fixture_all),
glob(true, pattern_plain, fixture_plain),
glob(true, pattern_multiple, fixture_multiple),
glob(true, pattern_prefix, fixture_prefix_suffix),
glob(true, pattern_suffix, fixture_prefix_suffix),
glob(true, pattern_prefix_suffix, fixture_prefix_suffix),
} { } {
g, err := New(test.pattern, test.delimiters...) g, err := New(test.pattern, test.delimiters...)
if err != nil { if err != nil {
t.Error(err) t.Errorf("parsing pattern %q error: %s", test.pattern, err)
continue continue
} }
@ -102,94 +131,53 @@ func TestGlob(t *testing.T) {
} }
} }
const Pattern = "*cat*eyes*"
const ExpPattern = ".*cat.*eyes.*"
const String = "my cat has very bright eyes"
const ProfPattern = "* ?at * eyes"
const ProfString = "my cat has very bright eyes"
//const Pattern = "*.google.com"
//const ExpPattern = ".*google\\.com"
//const String = "mail.google.com"
const PlainPattern = "google.com"
const PlainExpPattern = "google\\.com"
const PlainString = "google.com"
const PSPattern = "https://*.google.com"
const PSExpPattern = `https:\/\/[a-z]+\.google\\.com`
const PSString = "https://account.google.com"
func BenchmarkProf(b *testing.B) {
m, _ := New(Pattern)
func BenchmarkParse(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_ = m.Match(String) New(pattern_all)
} }
} }
func BenchmarkGobwas(b *testing.B) { func BenchmarkAll(b *testing.B) {
m, _ := New(Pattern) m, _ := New(pattern_all)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_ = m.Match(String) _ = m.Match(fixture_all)
}
}
func BenchmarkGobwasPlain(b *testing.B) {
m, _ := New(PlainPattern)
for i := 0; i < b.N; i++ {
_ = m.Match(PlainString)
}
}
func BenchmarkGobwasPrefix(b *testing.B) {
m, _ := New("abc*")
for i := 0; i < b.N; i++ {
_ = m.Match("abcdef")
}
}
func BenchmarkGobwasSuffix(b *testing.B) {
m, _ := New("*def")
for i := 0; i < b.N; i++ {
_ = m.Match("abcdef")
}
}
func BenchmarkGobwasPrefixSuffix(b *testing.B) {
m, _ := New("ab*ef")
for i := 0; i < b.N; i++ {
_ = m.Match("abcdef")
} }
} }
func BenchmarkRyanuber(b *testing.B) { func BenchmarkMultiple(b *testing.B) {
for i := 0; i < b.N; i++ { m, _ := New(pattern_multiple)
_ = rGlob.Glob(Pattern, String)
}
}
func BenchmarkRyanuberPlain(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = rGlob.Glob(PlainPattern, PlainString)
}
}
func BenchmarkRyanuberPrefixSuffix(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = rGlob.Glob(PSPattern, PSString)
}
}
for i := 0; i < b.N; i++ {
_ = m.Match(fixture_multiple)
}
}
func BenchmarkPlain(b *testing.B) {
m, _ := New(pattern_plain)
func BenchmarkRegExp(b *testing.B) {
r := regexp.MustCompile(ExpPattern)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_ = r.Match([]byte(String)) _ = m.Match(fixture_plain)
} }
} }
func BenchmarkRegExpPrefixSuffix(b *testing.B) { func BenchmarkPrefix(b *testing.B) {
r := regexp.MustCompile(PSExpPattern) m, _ := New(pattern_prefix)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_ = r.Match([]byte(PSString)) _ = m.Match(fixture_prefix_suffix)
}
}
func BenchmarkSuffix(b *testing.B) {
m, _ := New(pattern_suffix)
for i := 0; i < b.N; i++ {
_ = m.Match(fixture_prefix_suffix)
}
}
func BenchmarkPrefixSuffix(b *testing.B) {
m, _ := New(pattern_prefix_suffix)
for i := 0; i < b.N; i++ {
_ = m.Match(fixture_prefix_suffix)
} }
} }

View File

@ -7,8 +7,11 @@ import (
func indexByteNonEscaped(source string, needle, escape byte, shift int) int { func indexByteNonEscaped(source string, needle, escape byte, shift int) int {
i := strings.IndexByte(source, needle) i := strings.IndexByte(source, needle)
if i <= 0 { if i == -1 {
return i + shift return -1
}
if i == 0 {
return shift
} }
if source[i-1] != escape { if source[i-1] != escape {