forked from mirror/glob
commit
f565080178
|
@ -1,6 +1,7 @@
|
|||
package glob
|
||||
|
||||
// TODO use constructor with all matchers, and to their structs private
|
||||
// TODO glue multiple Text nodes (like after QuoteMeta)
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
19
glob.go
19
glob.go
|
@ -54,3 +54,22 @@ func MustCompile(pattern string, separators ...rune) Glob {
|
|||
|
||||
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) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Compile(pattern_all)
|
||||
|
@ -193,12 +226,12 @@ func BenchmarkAllGlobMismatch(b *testing.B) {
|
|||
_ = m.Match(fixture_all_mismatch)
|
||||
}
|
||||
}
|
||||
func BenchmarkAllGlobMatchParallel(b *testing.B) {
|
||||
func BenchmarkAllGlobMismatchParallel(b *testing.B) {
|
||||
m, _ := Compile(pattern_all)
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
@ -19,6 +20,20 @@ const (
|
|||
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
|
||||
|
||||
type stateFn func(*lexer) stateFn
|
||||
|
@ -124,7 +139,7 @@ func newLexer(source string) *lexer {
|
|||
l := &lexer{
|
||||
input: source,
|
||||
state: lexText,
|
||||
items: make(chan item, 5),
|
||||
items: make(chan item, len(source)),
|
||||
termPhrases: make(map[int]int),
|
||||
}
|
||||
return l
|
||||
|
@ -281,9 +296,7 @@ func lexText(l *lexer) stateFn {
|
|||
l.unread()
|
||||
l.emitMaybe(item_text)
|
||||
return lexSeparator
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if l.pos > l.start {
|
||||
|
|
|
@ -41,5 +41,5 @@ func (self Text) Index(s string) (int, []int) {
|
|||
}
|
||||
|
||||
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.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 ["."]
|
||||
g = glob.MustCompile("api.*.com", '.')
|
||||
g.Match("api.github.com") // true
|
||||
|
@ -76,7 +80,6 @@ func main() {
|
|||
g.Match("fat") // true
|
||||
g.Match("at") // false
|
||||
|
||||
|
||||
// create glob with pattern-alternatives list
|
||||
g = glob.MustCompile("{cat,bat,[fr]at}")
|
||||
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