mirror of https://github.com/gobwas/glob.git
commit
f565080178
|
@ -1,6 +1,7 @@
|
||||||
package glob
|
package glob
|
||||||
|
|
||||||
// TODO use constructor with all matchers, and to their structs private
|
// TODO use constructor with all matchers, and to their structs private
|
||||||
|
// TODO glue multiple Text nodes (like after QuoteMeta)
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
19
glob.go
19
glob.go
|
@ -54,3 +54,22 @@ func MustCompile(pattern string, separators ...rune) Glob {
|
||||||
|
|
||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QuoteMeta returns a string that quotes all glob pattern meta characters
|
||||||
|
// inside the argument text; For example, QuoteMeta(`{foo*}`) returns `\[foo\*\]`.
|
||||||
|
func QuoteMeta(s string) string {
|
||||||
|
b := make([]byte, 2*len(s))
|
||||||
|
|
||||||
|
// a byte loop is correct because all meta characters are ASCII
|
||||||
|
j := 0
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
if special(s[i]) {
|
||||||
|
b[j] = '\\'
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
b[j] = s[i]
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(b[0:j])
|
||||||
|
}
|
||||||
|
|
37
glob_test.go
37
glob_test.go
|
@ -150,6 +150,39 @@ func TestGlob(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestQuoteMeta(t *testing.T) {
|
||||||
|
specialsQuoted := make([]byte, len(specials)*2)
|
||||||
|
for i, j := 0, 0; i < len(specials); i, j = i+1, j+2 {
|
||||||
|
specialsQuoted[j] = '\\'
|
||||||
|
specialsQuoted[j+1] = specials[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
for id, test := range []struct {
|
||||||
|
in, out string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
in: `[foo*]`,
|
||||||
|
out: `\[foo\*\]`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: string(specials),
|
||||||
|
out: string(specialsQuoted),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: string(append([]byte("some text and"), specials...)),
|
||||||
|
out: string(append([]byte("some text and"), specialsQuoted...)),
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
act := QuoteMeta(test.in)
|
||||||
|
if act != test.out {
|
||||||
|
t.Errorf("#%d QuoteMeta(%q) = %q; want %q", id, test.in, act, test.out)
|
||||||
|
}
|
||||||
|
if _, err := Compile(act); err != nil {
|
||||||
|
t.Errorf("#%d _, err := Compile(QuoteMeta(%q) = %q); err = %q", id, test.in, act, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkParseGlob(b *testing.B) {
|
func BenchmarkParseGlob(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
Compile(pattern_all)
|
Compile(pattern_all)
|
||||||
|
@ -193,12 +226,12 @@ func BenchmarkAllGlobMismatch(b *testing.B) {
|
||||||
_ = m.Match(fixture_all_mismatch)
|
_ = m.Match(fixture_all_mismatch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func BenchmarkAllGlobMatchParallel(b *testing.B) {
|
func BenchmarkAllGlobMismatchParallel(b *testing.B) {
|
||||||
m, _ := Compile(pattern_all)
|
m, _ := Compile(pattern_all)
|
||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
_ = m.Match(fixture_all_match)
|
_ = m.Match(fixture_all_mismatch)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
19
lexer.go
19
lexer.go
|
@ -1,6 +1,7 @@
|
||||||
package glob
|
package glob
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
@ -19,6 +20,20 @@ const (
|
||||||
char_range_between = '-'
|
char_range_between = '-'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var specials = []byte{
|
||||||
|
char_any,
|
||||||
|
char_single,
|
||||||
|
char_escape,
|
||||||
|
char_range_open,
|
||||||
|
char_range_close,
|
||||||
|
char_terms_open,
|
||||||
|
char_terms_close,
|
||||||
|
}
|
||||||
|
|
||||||
|
func special(c byte) bool {
|
||||||
|
return bytes.IndexByte(specials, c) != -1
|
||||||
|
}
|
||||||
|
|
||||||
var eof rune = 0
|
var eof rune = 0
|
||||||
|
|
||||||
type stateFn func(*lexer) stateFn
|
type stateFn func(*lexer) stateFn
|
||||||
|
@ -124,7 +139,7 @@ func newLexer(source string) *lexer {
|
||||||
l := &lexer{
|
l := &lexer{
|
||||||
input: source,
|
input: source,
|
||||||
state: lexText,
|
state: lexText,
|
||||||
items: make(chan item, 5),
|
items: make(chan item, len(source)),
|
||||||
termPhrases: make(map[int]int),
|
termPhrases: make(map[int]int),
|
||||||
}
|
}
|
||||||
return l
|
return l
|
||||||
|
@ -281,9 +296,7 @@ func lexText(l *lexer) stateFn {
|
||||||
l.unread()
|
l.unread()
|
||||||
l.emitMaybe(item_text)
|
l.emitMaybe(item_text)
|
||||||
return lexSeparator
|
return lexSeparator
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.pos > l.start {
|
if l.pos > l.start {
|
||||||
|
|
|
@ -41,5 +41,5 @@ func (self Text) Index(s string) (int, []int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self Text) String() string {
|
func (self Text) String() string {
|
||||||
return fmt.Sprintf("<text:%s>", self.Str)
|
return fmt.Sprintf("<text:`%v`>", self.Str)
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,10 @@ func main() {
|
||||||
g = glob.MustCompile("*.github.com")
|
g = glob.MustCompile("*.github.com")
|
||||||
g.Match("api.github.com") // true
|
g.Match("api.github.com") // true
|
||||||
|
|
||||||
|
// quote meta characters and then create simple glob
|
||||||
|
g = glob.MustCompile(glob.QuoteMeta("*.github.com"))
|
||||||
|
g.Match("*.github.com") // true
|
||||||
|
|
||||||
// create new glob with set of delimiters as ["."]
|
// create new glob with set of delimiters as ["."]
|
||||||
g = glob.MustCompile("api.*.com", '.')
|
g = glob.MustCompile("api.*.com", '.')
|
||||||
g.Match("api.github.com") // true
|
g.Match("api.github.com") // true
|
||||||
|
@ -76,7 +80,6 @@ func main() {
|
||||||
g.Match("fat") // true
|
g.Match("fat") // true
|
||||||
g.Match("at") // false
|
g.Match("at") // false
|
||||||
|
|
||||||
|
|
||||||
// create glob with pattern-alternatives list
|
// create glob with pattern-alternatives list
|
||||||
g = glob.MustCompile("{cat,bat,[fr]at}")
|
g = glob.MustCompile("{cat,bat,[fr]at}")
|
||||||
g.Match("cat") // true
|
g.Match("cat") // true
|
||||||
|
|
26
todo.txt
26
todo.txt
|
@ -1,26 +0,0 @@
|
||||||
benchmark old ns/op new ns/op delta
|
|
||||||
|
|
||||||
BenchmarkAllGlobMatch-4 519 1024 +97.30%
|
|
||||||
BenchmarkMultipleGlobMatch-4 123 218 +77.24%
|
|
||||||
BenchmarkAlternativesGlobMatch-4 164 283 +72.56%
|
|
||||||
BenchmarkAlternativesSuffixFirstGlobMatch-4 23.6 23.5 -0.42%
|
|
||||||
BenchmarkAlternativesSuffixSecondGlobMatch-4 29.7 30.1 +1.35%
|
|
||||||
BenchmarkAlternativesCombineLiteGlobMatch-4 161 352 +118.63%
|
|
||||||
BenchmarkAlternativesCombineHardGlobMatch-4 321 649 +102.18%
|
|
||||||
BenchmarkPlainGlobMatch-4 7.17 7.09 -1.12%
|
|
||||||
BenchmarkPrefixGlobMatch-4 8.74 8.64 -1.14%
|
|
||||||
BenchmarkSuffixGlobMatch-4 10.3 9.06 -12.04%
|
|
||||||
BenchmarkPrefixSuffixGlobMatch-4 31.0 15.1 -51.29%
|
|
||||||
BenchmarkIndexAny-4 1414 232 -83.59%
|
|
||||||
BenchmarkIndexContains-4 557 250 -55.12%
|
|
||||||
BenchmarkIndexList-4 207 42.6 -79.42%
|
|
||||||
BenchmarkIndexMax-4 630 111 -82.38%
|
|
||||||
BenchmarkIndexMin-4 515 328 -36.31%
|
|
||||||
BenchmarkIndexPrefixSuffix-4 97.9 86.2 -11.95%
|
|
||||||
BenchmarkIndexPrefix-4 86.1 84.0 -2.44%
|
|
||||||
BenchmarkIndexRange-4 181 144 -20.44%
|
|
||||||
BenchmarkRowIndex-4 185 127 -31.35%
|
|
||||||
BenchmarkIndexSingle-4 82.6 16.0 -80.63%
|
|
||||||
BenchmarkIndexSuffix-4 85.5 84.9 -0.70%
|
|
||||||
BenchmarkIndexSuper-4 450 196 -56.44%
|
|
||||||
BenchmarkIndexText-4 85.3 85.9 +0.70%
|
|
Loading…
Reference in New Issue