I wrote something similar but much more limited (only supporting *) for a project I was working on a while ago, I donβt know if its particularly efficient but I find it interesting to see the different approaches.
pub fn wildcardMatch(pattern: []const u8, value: []const u8) bool {
if (pattern.len == 0 or pattern.ptr == value.ptr) return true;
var has_carded = false;
var partial_match = false;
var currently_carding = false;
var i: usize = 0;
outer: for (pattern) |e| {
if (e == '*') {
partial_match = false;
currently_carding = true;
has_carded = true;
continue;
}
for (value[i..]) |v| {
i += 1;
if (e == v) {
partial_match = currently_carding;
currently_carding = false;
continue :outer;
}
if (currently_carding) continue;
if (partial_match) {
partial_match = false;
currently_carding = true;
has_carded = true;
continue;
}
return false;
}
return false;
}
return has_carded or pattern.len == value.len;
}
test "wildcardMatch" {
try std.testing.expect(!wildcardMatch("te", "test"));
try std.testing.expect(!wildcardMatch("te", "t"));
try std.testing.expect(wildcardMatch("", "test"));
try std.testing.expect(wildcardMatch("te*", "test"));
try std.testing.expect(wildcardMatch("*st", "test"));
try std.testing.expect(wildcardMatch("t*t", "test"));
try std.testing.expect(!wildcardMatch("te*", "west"));
try std.testing.expect(!wildcardMatch("*st", "tesw"));
try std.testing.expect(!wildcardMatch("t*t", "west"));
try std.testing.expect(!wildcardMatch("*st", "tewt"));
try std.testing.expect(!wildcardMatch("t*t", "tesw"));
try std.testing.expect(wildcardMatch("*test*", "ingtestingtesting"));
try std.testing.expect(wildcardMatch("*test*", "test"));
try std.testing.expect(!wildcardMatch("*test*", "inginging"));
try std.testing.expect(wildcardMatch("da*da*da*", "daaadabadmanda"));
try std.testing.expect(!wildcardMatch("test.ing", "tester.ing"));
}