Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 32 additions & 25 deletions glob.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,52 +5,59 @@ import "strings"
// The character which is treated like a glob
const GLOB = "*"

// Glob will test a string pattern, potentially containing globs, against a
// subject string. The result is a simple true/false, determining whether or
// not the glob pattern matched the subject text.
func Glob(pattern, subj string) bool {
// Compile will prepare a string pattern and return a function for further matching.
func Compile(pattern string) func(subj string) bool {
// Empty pattern can only match empty subject
if pattern == "" {
return subj == pattern
return func(subj string) bool { return subj == "" }
}

// If the pattern _is_ a glob, it matches everything
if pattern == GLOB {
return true
return func(subj string) bool { return true }
}

parts := strings.Split(pattern, GLOB)

if len(parts) == 1 {
// No globs in pattern, so test for equality
return subj == pattern
return func(subj string) bool { return subj == pattern }
}

leadingGlob := strings.HasPrefix(pattern, GLOB)
trailingGlob := strings.HasSuffix(pattern, GLOB)
end := len(parts) - 1

// Go over the leading parts and ensure they match.
for i := 0; i < end; i++ {
idx := strings.Index(subj, parts[i])

switch i {
case 0:
// Check the first section. Requires special handling.
if !leadingGlob && idx != 0 {
return false
}
default:
// Check that the middle parts match.
if idx < 0 {
return false
return func(subj string) bool {
// Go over the leading parts and ensure they match.
for i := 0; i < end; i++ {
idx := strings.Index(subj, parts[i])

switch i {
case 0:
// Check the first section. Requires special handling.
if !leadingGlob && idx != 0 {
return false
}
default:
// Check that the middle parts match.
if idx < 0 {
return false
}
}

// Trim evaluated text from subj as we loop over the pattern.
subj = subj[idx+len(parts[i]):]
}

// Trim evaluated text from subj as we loop over the pattern.
subj = subj[idx+len(parts[i]):]
// Reached the last section. Requires special handling.
return trailingGlob || strings.HasSuffix(subj, parts[end])
}
}

// Reached the last section. Requires special handling.
return trailingGlob || strings.HasSuffix(subj, parts[end])
// Glob will test a string pattern, potentially containing globs, against a
// subject string. The result is a simple true/false, determining whether or
// not the glob pattern matched the subject text.
func Glob(pattern, subj string) bool {
return Compile(pattern)(subj)
}
10 changes: 10 additions & 0 deletions glob_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,13 @@ func BenchmarkGlob(b *testing.B) {
}
}
}

func BenchmarkCompiledGlob(b *testing.B) {
compiledGlob := Compile("*quick*fox*dog")
b.ResetTimer()
for i := 0; i < b.N; i++ {
if !compiledGlob("The quick brown fox jumped over the lazy dog") {
b.Fatalf("should match")
}
}
}