Merge pull request #5 from gobwas/feature/quote

Feature/quote
This commit is contained in:
Sergey Kamardin 2016-02-25 00:43:22 +03:00
commit f565080178
7 changed files with 76 additions and 33 deletions

View File

@ -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
View File

@ -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])
}

View File

@ -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)
}
})
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -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

View File

@ -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%