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

20
glob.go
View File

@ -2,8 +2,8 @@ package glob
import (
"strings"
"errors"
"github.com/gobwas/glob/match"
"fmt"
)
const (
@ -96,7 +96,7 @@ func parse(str string, sep string, st state) ([]token, error) {
case range_open:
closed := indexByteNonEscaped(str, range_close, escape, 0)
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]
@ -135,6 +135,7 @@ func parseRange(def string) (match.Matcher, error) {
not bool
esc bool
minus bool
minusIndex int
b []byte
)
@ -152,26 +153,31 @@ func parseRange(def string) (match.Matcher, error) {
}
case escape:
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
case inside_range_minus:
minus = true
minusIndex = len(b)
default:
b = append(b, c)
}
}
if len(b) == 0 {
return nil, fmt.Errorf("range could not be empty")
}
def = string(b)
if minus {
r := []rune(def)
if len(r) != 3 || r[1] != inside_range_minus {
return nil, errors.New("invalid range syntax")
if len(r) != 2 || minusIndex != 1 {
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
@ -185,4 +191,4 @@ type token struct {
type state struct {
escape bool
tokens []token
}
}

View File

@ -1,11 +1,26 @@
package glob
import (
rGlob "github.com/ryanuber/go-glob"
"regexp"
"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 {
pattern, match string
should bool
@ -16,7 +31,7 @@ func glob(s bool, p, m string, d ...string) test {
return test{p, m, s, d}
}
func TestIndexOfNonEscaped(t *testing.T) {
func TestIndexByteNonEscaped(t *testing.T) {
for _, test := range []struct {
s string
n, e byte
@ -46,6 +61,12 @@ func TestIndexOfNonEscaped(t *testing.T) {
'\\',
-1,
},
{
"\\b",
'b',
'\\',
-1,
},
} {
i := indexByteNonEscaped(test.s, test.n, test.e, 0)
if i != test.i {
@ -88,10 +109,18 @@ func TestGlob(t *testing.T) {
glob(false, "*is", "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...)
if err != nil {
t.Error(err)
t.Errorf("parsing pattern %q error: %s", test.pattern, err)
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++ {
_ = m.Match(String)
New(pattern_all)
}
}
func BenchmarkGobwas(b *testing.B) {
m, _ := New(Pattern)
func BenchmarkAll(b *testing.B) {
m, _ := New(pattern_all)
for i := 0; i < b.N; i++ {
_ = m.Match(String)
}
}
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")
_ = m.Match(fixture_all)
}
}
func BenchmarkRyanuber(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = 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)
}
}
func BenchmarkMultiple(b *testing.B) {
m, _ := New(pattern_multiple)
func BenchmarkRegExp(b *testing.B) {
r := regexp.MustCompile(ExpPattern)
for i := 0; i < b.N; i++ {
_ = r.Match([]byte(String))
_ = m.Match(fixture_multiple)
}
}
func BenchmarkRegExpPrefixSuffix(b *testing.B) {
r := regexp.MustCompile(PSExpPattern)
func BenchmarkPlain(b *testing.B) {
m, _ := New(pattern_plain)
for i := 0; i < b.N; i++ {
_ = r.Match([]byte(PSString))
_ = m.Match(fixture_plain)
}
}
func BenchmarkPrefix(b *testing.B) {
m, _ := New(pattern_prefix)
for i := 0; i < b.N; i++ {
_ = 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 {
i := strings.IndexByte(source, needle)
if i <= 0 {
return i + shift
if i == -1 {
return -1
}
if i == 0 {
return shift
}
if source[i-1] != escape {