diff options
author | howar6hill <f.eiwu@yahoo.com> | 2020-02-26 15:25:24 +0800 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-03-02 10:38:08 +0100 |
commit | 055344f3461a28578f8b49e9f2431bb9f22936b4 (patch) | |
tree | 4a39e875cef56df1950d56a2dd385898f0d000fc /AK/StringUtils.cpp | |
parent | 2a30a020c13e462cba6e197f92a3171d79b12ba2 (diff) | |
download | serenity-055344f3461a28578f8b49e9f2431bb9f22936b4.zip |
AK: Move the wildcard-matching implementation to StringUtils
Provide wrappers in the String and StringView classes, and add some tests.
Diffstat (limited to 'AK/StringUtils.cpp')
-rw-r--r-- | AK/StringUtils.cpp | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/AK/StringUtils.cpp b/AK/StringUtils.cpp new file mode 100644 index 0000000000..fe37f49e0b --- /dev/null +++ b/AK/StringUtils.cpp @@ -0,0 +1,64 @@ +#include <AK/String.h> +#include <AK/StringUtils.h> +#include <AK/StringView.h> + +namespace AK { + +namespace StringUtils { + + bool matches(const StringView& str, const StringView& mask, CaseSensitivity case_sensitivity) + { + if (str.is_null() || mask.is_null()) + return str.is_null() && mask.is_null(); + + if (case_sensitivity == CaseSensitivity::CaseInsensitive) { + const String str_lower = String(str).to_lowercase(); + const String mask_lower = String(mask).to_lowercase(); + return matches(str_lower, mask_lower, CaseSensitivity::CaseSensitive); + } + + const char* string_ptr = str.characters_without_null_termination(); + const char* string_end = string_ptr + str.length(); + const char* mask_ptr = mask.characters_without_null_termination(); + const char* mask_end = mask_ptr + mask.length(); + + // Match string against mask directly unless we hit a * + while ((string_ptr < string_end) && (mask_ptr < mask_end) && (*mask_ptr != '*')) { + if ((*mask_ptr != *string_ptr) && (*mask_ptr != '?')) + return false; + mask_ptr++; + string_ptr++; + } + + const char* cp = nullptr; + const char* mp = nullptr; + + while (string_ptr < string_end) { + if ((mask_ptr < mask_end) && (*mask_ptr == '*')) { + // If we have only a * left, there is no way to not match. + if (++mask_ptr == mask_end) + return true; + mp = mask_ptr; + cp = string_ptr + 1; + } else if ((mask_ptr < mask_end) && ((*mask_ptr == *string_ptr) || (*mask_ptr == '?'))) { + mask_ptr++; + string_ptr++; + } else if ((cp != nullptr) && (mp != nullptr)) { + mask_ptr = mp; + string_ptr = cp++; + } else { + break; + } + } + + // Handle any trailing mask + while ((mask_ptr < mask_end) && (*mask_ptr == '*')) + mask_ptr++; + + // If we 'ate' all of the mask and the string then we match. + return (mask_ptr == mask_end) && string_ptr == string_end; + } + +} + +} |