wildcard matcher

This commit is contained in:
Nikita Smith
2026-04-22 09:30:45 -07:00
committed by Ryan Fleury
parent ffc6905b06
commit 4786dc419a
3 changed files with 143 additions and 0 deletions
+70
View File
@@ -325,6 +325,76 @@ str8_match(String8 a, String8 b, StringMatchFlags flags)
return result; return result;
} }
internal B32
str8_char_match(U8 a, U8 b, StringMatchFlags flags)
{
U8 at = a;
U8 bt = b;
if (flags & StringMatchFlag_CaseInsensitive) {
at = upper_from_char(at);
bt = upper_from_char(bt);
}
if (flags & StringMatchFlag_SlashInsensitive) {
if (at == '\\') { at = '/'; }
if (bt == '\\') { bt = '/'; }
}
return (at == bt);
}
internal B32
str8_match_wildcard(String8 string, String8 pattern, StringMatchFlags flags)
{
B32 matched = 0;
U64 pattern_cursor = 0;
U64 string_cursor = 0;
U64 pattern_start = max_U64;
U64 string_start = 0;
for (;;) {
if (pattern_cursor == pattern.size) {
if (string_cursor == string.size || (flags & StringMatchFlag_RightSideSloppy)) {
matched = 1;
break;
}
}
if (string_cursor == string.size) {
while (pattern_cursor < pattern.size && pattern.str[pattern_cursor] == '*') {
pattern_cursor += 1;
}
matched = (pattern_cursor == pattern.size);
break;
}
if (pattern_cursor < pattern.size && pattern.str[pattern_cursor] == '*') {
pattern_start = pattern_cursor;
string_start = string_cursor;
pattern_cursor += 1;
continue;
}
if (pattern_cursor < pattern.size && (pattern.str[pattern_cursor] == '?' || str8_char_match(string.str[string_cursor], pattern.str[pattern_cursor], flags))) {
string_cursor += 1;
pattern_cursor += 1;
continue;
}
if (pattern_start != max_U64) {
pattern_cursor = pattern_start + 1;
string_start += 1;
string_cursor = string_start;
continue;
}
break;
}
return matched;
}
internal U64 internal U64
str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags) str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags)
{ {
+1
View File
@@ -197,6 +197,7 @@ internal String8 backslashed_from_str8(Arena *arena, String8 string);
#define str8_match_lit(a_lit, b, flags) str8_match(str8_lit(a_lit), (b), (flags)) #define str8_match_lit(a_lit, b, flags) str8_match(str8_lit(a_lit), (b), (flags))
#define str8_match_cstr(a_cstr, b, flags) str8_match(str8_cstring(a_cstr), (b), (flags)) #define str8_match_cstr(a_cstr, b, flags) str8_match(str8_cstring(a_cstr), (b), (flags))
internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags); internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags);
internal B32 str8_match_wildcard(String8 string, String8 pattern, StringMatchFlags flags);
internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags); internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
internal U64 str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags); internal U64 str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
internal B32 str8_is_before(String8 a, String8 b); internal B32 str8_is_before(String8 a, String8 b);
+72
View File
@@ -104,4 +104,76 @@ TEST(count_digits)
T_Ok(count_digits_u64(999999, 10) == 6); T_Ok(count_digits_u64(999999, 10) == 6);
} }
TEST(match_wildcard)
{
// empty strings
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit(""), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("**"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("?"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*?"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("?*"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit(""), 0) == 0);
// exact
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("a"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("A"), 0) == 0);
// ?
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("?"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("?"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("?"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("a?"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("?b"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("??"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a?c"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("???"), 0) == 0);
// *
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*c"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*b*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a*c"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("b*"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("**"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a**c"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a*b*c"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*a*d*"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("abcd"), str8_lit("a*d"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abefcdgiescdfimde"), str8_lit("ab*cd?i*de"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("mississippi"), str8_lit("m*iss*ppi"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*b"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("aa"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("aa"), str8_lit("a"), 0) == 0);
// case insensitive
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("A"), StringMatchFlag_CaseInsensitive) == 1);
T_Ok(str8_match_wildcard(str8_lit("FooBar"), str8_lit("foobar"), StringMatchFlag_CaseInsensitive) == 1);
T_Ok(str8_match_wildcard(str8_lit("Foobar"), str8_lit("foo*"), StringMatchFlag_CaseInsensitive) == 1);
// right side sloppy
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("ab"), StringMatchFlag_RightSideSloppy) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit(""), StringMatchFlag_RightSideSloppy) == 1);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("a"), StringMatchFlag_RightSideSloppy) == 0);
// slash insensitive
T_Ok(str8_match_wildcard(str8_lit("a/b"), str8_lit("a\\b"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("a/b"), str8_lit("a\\b"), StringMatchFlag_SlashInsensitive) == 1);
T_Ok(str8_match_wildcard(str8_lit("a/b/c"), str8_lit("a\\*\\c"), StringMatchFlag_SlashInsensitive) == 1);
// combined
T_Ok(str8_match_wildcard(str8_lit("Ab\\Cde"), str8_lit("ab/*e"), StringMatchFlag_CaseInsensitive|StringMatchFlag_SlashInsensitive) == 1);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*?*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("*?*"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*?*"), 0) == 0);
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("?*?"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("?*?"), 0) == 1);
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("?*?"), 0) == 0);
}
#undef T_Group #undef T_Group