From 5df6e78d3b8b2182fc7b53597e35b06d6234afe4 Mon Sep 17 00:00:00 2001 From: Kyle Sanderson Date: Sun, 20 Oct 2024 04:03:52 -0700 Subject: [PATCH] fix(wildcard): partial match ignoring consumed pattern (#1765) * tests(wildcard): ? * really? * Franklin * remember when regex was easy * == * why not. * I need an adult. * Update match_test.go * tests + readability * back to basics --- pkg/wildcard/match.go | 52 ++++++++++++++++++++++---------------- pkg/wildcard/match_test.go | 22 ++++++++++++++++ 2 files changed, 52 insertions(+), 22 deletions(-) diff --git a/pkg/wildcard/match.go b/pkg/wildcard/match.go index 8e0e2b9..94fe998 100644 --- a/pkg/wildcard/match.go +++ b/pkg/wildcard/match.go @@ -41,28 +41,7 @@ func match(pattern, name string, simple bool) (matched bool) { ((wildEnd && strings.Count(pattern, "*") == 1) || // egg?bert* (len(pattern) == len(name) && !strings.Contains(pattern, "*"))) { // egg?bert? - base := 0 - for base < len(name) { - i := strings.IndexRune(pattern[base:], '?') - if i == -1 { - if (wildEnd && !strings.HasPrefix(name[base:], pattern[base:len(pattern)-1])) || // egg* - (!wildEnd && name[base:] != pattern[base:]) { // egg - break - } - - base = len(name) - continue - } - - offset := base + i - if len(name) < offset || name[base:offset] != pattern[base:offset] { - break - } - - base = offset + 1 - } - - return base == len(name) + return matchComplex(name, pattern, wildEnd) } else if strings.HasPrefix(pattern, "*") && strings.HasSuffix(pattern, "*") && // *egg* (simple || (!simple && !strings.Contains(pattern, "?"))) && // simple is fine, if not we need to check for ? and skip if so. strings.Count(pattern, "*") == 2 { // make sure that we have no other wildcards. @@ -72,6 +51,35 @@ func match(pattern, name string, simple bool) (matched bool) { return deepMatchRune(name, pattern, simple, pattern, false) } +func matchComplex(name, pattern string, wildEnd bool) bool { + base := 0 + consumedPattern := 0 + + for base < len(name) && consumedPattern < len(pattern) { + i := strings.IndexRune(pattern[base:], '?') + if i == -1 { + if (wildEnd && !strings.HasPrefix(name[base:], pattern[base:len(pattern)-1])) || // egg* + (!wildEnd && name[base:] != pattern[base:]) { // egg + break + } + + base = len(name) + consumedPattern = len(pattern) + continue + } + + offset := base + i + if len(name) < offset || name[base:offset] != pattern[base:offset] { + break + } + + base = offset + 1 + consumedPattern = base + } + + return base == len(name) && consumedPattern == len(pattern) +} + func MatchSliceSimple(pattern []string, name string) (matched bool) { return matchSlice(pattern, name, true) } diff --git a/pkg/wildcard/match_test.go b/pkg/wildcard/match_test.go index 04e56c7..a1fa2ae 100644 --- a/pkg/wildcard/match_test.go +++ b/pkg/wildcard/match_test.go @@ -107,6 +107,26 @@ func TestMatch(t *testing.T) { text: "them", matched: false, }, + { + pattern: "t?q*", + text: "tam e", + matched: false, + }, + { + pattern: "Hard?Quiz*", + text: "HardX 24 10 12 Ella Reese XXX 1080p MP4-WRB", + matched: false, + }, + { + pattern: "Hard?Quiz*", + text: "HardX", + matched: false, + }, + { + pattern: "T?Q*", + text: "T?Q", + matched: true, + }, } // Iterating over the test cases, call the function under test and assert the output. for i, testCase := range testCases { @@ -157,6 +177,7 @@ func TestMatchSliceSimple(t *testing.T) { }{ {[]string{"*", "test"}, "test", true}, {[]string{"te?t", "tost", "random"}, "tost", true}, + {[]string{"te?t", "t?s?", "random"}, "tost", false}, {[]string{"*st", "n?st", "l*st"}, "list", true}, {[]string{"?", "?*", "?**"}, "t", false}, {[]string{"a", "b", "c"}, "d", false}, @@ -182,6 +203,7 @@ func TestMatchSlice(t *testing.T) { }{ {[]string{"*", "test", "t?st"}, "test", true}, {[]string{"te?t", "t?st", "random"}, "tost", true}, + {[]string{"te?t", "t?s?", "random"}, "tost", true}, {[]string{"te?t", "t??e?", "random"}, "toser", true}, {[]string{"*st", "n?st", "l*st"}, "list", true}, {[]string{"?", "??", "???"}, "t", true},