Merge pull request #90678 from raulsntos/dotnet/StringExtensions.Match

C#: Fix ExprMatch for case sensitive matching
This commit is contained in:
Rémi Verschelde 2024-04-15 18:14:45 +02:00
commit 8a3195ef56
No known key found for this signature in database
GPG key ID: C3336907360768E1

View file

@ -1208,39 +1208,39 @@ namespace Godot
/// Do a simple expression match, where '*' matches zero or more /// Do a simple expression match, where '*' matches zero or more
/// arbitrary characters and '?' matches any single character except '.'. /// arbitrary characters and '?' matches any single character except '.'.
/// </summary> /// </summary>
/// <param name="instance">The string to check.</param> /// <param name="str">The string to check.</param>
/// <param name="expr">Expression to check.</param> /// <param name="pattern">Expression to check.</param>
/// <param name="caseSensitive"> /// <param name="caseSensitive">
/// If <see langword="true"/>, the check will be case sensitive. /// If <see langword="true"/>, the check will be case sensitive.
/// </param> /// </param>
/// <returns>If the expression has any matches.</returns> /// <returns>If the expression has any matches.</returns>
private static bool ExprMatch(this string instance, string expr, bool caseSensitive) private static bool WildcardMatch(ReadOnlySpan<char> str, ReadOnlySpan<char> pattern, bool caseSensitive)
{ {
// case '\0': // case '\0':
if (expr.Length == 0) if (pattern.IsEmpty)
return instance.Length == 0; return str.IsEmpty;
switch (expr[0]) switch (pattern[0])
{ {
case '*': case '*':
return ExprMatch(instance, expr.Substring(1), caseSensitive) || (instance.Length > 0 && return WildcardMatch(str, pattern.Slice(1), caseSensitive)
ExprMatch(instance.Substring(1), expr, caseSensitive)); || (!str.IsEmpty && WildcardMatch(str.Slice(1), pattern, caseSensitive));
case '?': case '?':
return instance.Length > 0 && instance[0] != '.' && return !str.IsEmpty && str[0] != '.' &&
ExprMatch(instance.Substring(1), expr.Substring(1), caseSensitive); WildcardMatch(str.Slice(1), pattern.Slice(1), caseSensitive);
default: default:
if (instance.Length == 0) if (str.IsEmpty)
return false; return false;
if (caseSensitive) bool charMatches = caseSensitive ?
return instance[0] == expr[0]; str[0] == pattern[0] :
return (char.ToUpperInvariant(instance[0]) == char.ToUpperInvariant(expr[0])) && char.ToUpperInvariant(str[0]) == char.ToUpperInvariant(pattern[0]);
ExprMatch(instance.Substring(1), expr.Substring(1), caseSensitive); return charMatches &&
WildcardMatch(str.Slice(1), pattern.Slice(1), caseSensitive);
} }
} }
/// <summary> /// <summary>
/// Do a simple case sensitive expression match, using ? and * wildcards /// Do a simple case sensitive expression match, using ? and * wildcards.
/// (see <see cref="ExprMatch(string, string, bool)"/>).
/// </summary> /// </summary>
/// <seealso cref="MatchN(string, string)"/> /// <seealso cref="MatchN(string, string)"/>
/// <param name="instance">The string to check.</param> /// <param name="instance">The string to check.</param>
@ -1254,12 +1254,11 @@ namespace Godot
if (instance.Length == 0 || expr.Length == 0) if (instance.Length == 0 || expr.Length == 0)
return false; return false;
return instance.ExprMatch(expr, caseSensitive); return WildcardMatch(instance, expr, caseSensitive);
} }
/// <summary> /// <summary>
/// Do a simple case insensitive expression match, using ? and * wildcards /// Do a simple case insensitive expression match, using ? and * wildcards.
/// (see <see cref="ExprMatch(string, string, bool)"/>).
/// </summary> /// </summary>
/// <seealso cref="Match(string, string, bool)"/> /// <seealso cref="Match(string, string, bool)"/>
/// <param name="instance">The string to check.</param> /// <param name="instance">The string to check.</param>
@ -1270,7 +1269,7 @@ namespace Godot
if (instance.Length == 0 || expr.Length == 0) if (instance.Length == 0 || expr.Length == 0)
return false; return false;
return instance.ExprMatch(expr, caseSensitive: false); return WildcardMatch(instance, expr, caseSensitive: false);
} }
/// <summary> /// <summary>