From b32279b87bb02dcdf5d613bf48315968297b8972 Mon Sep 17 00:00:00 2001 From: vodkaslime <646329483@qq.com> Date: Mon, 26 Sep 2022 10:51:48 +0800 Subject: [PATCH] matcher struct to tune wildcard chars --- README.md | 3 +++ wildcard.go | 25 +++++++++++++++++++------ wildcard_test.go | 41 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..c58dd97 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# wildcard + +A simple golang wildcard matcher. Golang has pretty well built regex functionalities, but it does not have wildcard matcher that works as nicely. Therefore this package serves the need to check whether a string matches a pattern in the rule of wildcard. \ No newline at end of file diff --git a/wildcard.go b/wildcard.go index 9f10884..c71e089 100644 --- a/wildcard.go +++ b/wildcard.go @@ -2,9 +2,21 @@ package wildcard import "strings" -func Match(pattern string, s string) (bool, error) { +type Matcher struct { + S byte + M byte +} + +func NewMatcher() *Matcher { + return &Matcher{ + S: '?', + M: '*', + } +} + +func (m *Matcher) Match(pattern string, s string) (bool, error) { // Edge cases. - if pattern == "*" { + if pattern == string(m.M) { return true, nil } @@ -17,7 +29,8 @@ func Match(pattern string, s string) (bool, error) { // If pattern does not contain wildcard chars, just compare the strings // to avoid extra memory allocation. - if !strings.Contains(pattern, "*") && !strings.Contains(pattern, ".") { + if !strings.Contains(pattern, string(m.M)) && + !strings.Contains(pattern, string(m.S)) { return pattern == s, nil } @@ -32,7 +45,7 @@ func Match(pattern string, s string) (bool, error) { dp[0][0] = true for i := 0; i < lp; i++ { - if pattern[i] == '*' { + if pattern[i] == m.M { dp[i+1][0] = dp[i][0] } else { dp[i+1][0] = false @@ -49,9 +62,9 @@ func Match(pattern string, s string) (bool, error) { pc := pattern[i] sc := s[j] switch pattern[i] { - case '*': + case m.M: dp[i+1][j+1] = dp[i][j] || dp[i][j+1] || dp[i+1][j] - case '.': + case m.S: dp[i+1][j+1] = dp[i][j] default: if pc == sc { diff --git a/wildcard_test.go b/wildcard_test.go index 03084db..dd2f5ac 100644 --- a/wildcard_test.go +++ b/wildcard_test.go @@ -14,7 +14,36 @@ type testCase struct { func TestMatch(t *testing.T) { - testCases := []testCase{ + testCases1 := []testCase{ + {"", "", true}, + {"*", "", true}, + {"?", "", false}, + {"", "a", false}, + {"abc", "abc", true}, + {"abc", "ac", false}, + {"abc", "abd", false}, + {"a?c", "abc", true}, + {"a*c", "abc", true}, + {"a*c", "abcbc", true}, + {"a*c", "abcbd", false}, + {"a*b??c", "ajcbjcklbjic", true}, + {"a*b??c", "ajcbjcklbjimc", false}, + {"a*b*c", "ajkembbcldkcedc", true}, + } + + m1 := NewMatcher() + for _, tc := range testCases1 { + m, err := m1.Match(tc.p, tc.s) + if !assert.Equal(t, m, tc.m) { + println(tc.p, tc.s, tc.m) + } + assert.Nil(t, err) + } + + m2 := NewMatcher() + m2.S = '.' + + testCases2 := []testCase{ {"", "", true}, {"*", "", true}, {".", "", false}, @@ -23,17 +52,21 @@ func TestMatch(t *testing.T) { {"abc", "ac", false}, {"abc", "abd", false}, {"a.c", "abc", true}, + {"a?c", "abc", false}, {"a*c", "abc", true}, {"a*c", "abcbc", true}, {"a*c", "abcbd", false}, {"a*b..c", "ajcbjcklbjic", true}, + {"a*b.?c", "ajcbjcklbjic", false}, {"a*b..c", "ajcbjcklbjimc", false}, {"a*b*c", "ajkembbcldkcedc", true}, } - for _, tc := range testCases { - m, err := Match(tc.p, tc.s) - assert.Equal(t, m, tc.m) + for _, tc := range testCases2 { + m, err := m2.Match(tc.p, tc.s) + if !assert.Equal(t, m, tc.m) { + println(tc.p, tc.s, tc.m) + } assert.Nil(t, err) } }