mirror of https://github.com/gobwas/glob.git
fix
This commit is contained in:
parent
5b4ed87b27
commit
e39827db7b
18
glob.go
18
glob.go
|
@ -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
|
||||||
|
|
124
glob_test.go
124
glob_test.go
|
@ -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"
|
func BenchmarkParse(b *testing.B) {
|
||||||
const ProfString = "my cat has very bright eyes"
|
for i := 0; i < b.N; i++ {
|
||||||
|
New(pattern_all)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//const Pattern = "*.google.com"
|
func BenchmarkAll(b *testing.B) {
|
||||||
//const ExpPattern = ".*google\\.com"
|
m, _ := New(pattern_all)
|
||||||
//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)
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = m.Match(String)
|
_ = m.Match(fixture_all)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkGobwas(b *testing.B) {
|
func BenchmarkMultiple(b *testing.B) {
|
||||||
m, _ := New(Pattern)
|
m, _ := New(pattern_multiple)
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = m.Match(String)
|
_ = m.Match(fixture_multiple)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func BenchmarkGobwasPlain(b *testing.B) {
|
func BenchmarkPlain(b *testing.B) {
|
||||||
m, _ := New(PlainPattern)
|
m, _ := New(pattern_plain)
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = m.Match(PlainString)
|
_ = m.Match(fixture_plain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func BenchmarkGobwasPrefix(b *testing.B) {
|
func BenchmarkPrefix(b *testing.B) {
|
||||||
m, _ := New("abc*")
|
m, _ := New(pattern_prefix)
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = m.Match("abcdef")
|
_ = m.Match(fixture_prefix_suffix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func BenchmarkGobwasSuffix(b *testing.B) {
|
func BenchmarkSuffix(b *testing.B) {
|
||||||
m, _ := New("*def")
|
m, _ := New(pattern_suffix)
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = m.Match("abcdef")
|
_ = m.Match(fixture_prefix_suffix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func BenchmarkGobwasPrefixSuffix(b *testing.B) {
|
func BenchmarkPrefixSuffix(b *testing.B) {
|
||||||
m, _ := New("ab*ef")
|
m, _ := New(pattern_prefix_suffix)
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = m.Match("abcdef")
|
_ = m.Match(fixture_prefix_suffix)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 BenchmarkRegExp(b *testing.B) {
|
|
||||||
r := regexp.MustCompile(ExpPattern)
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
_ = r.Match([]byte(String))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func BenchmarkRegExpPrefixSuffix(b *testing.B) {
|
|
||||||
r := regexp.MustCompile(PSExpPattern)
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
_ = r.Match([]byte(PSString))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
7
util.go
7
util.go
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue