namespace FluidExplorer.Services.Search.Usn; /// /// 通配符匹配器:? 匹配任意单字符,* 匹配任意长度(含空), /// 大小写不敏感(用固定区域的大小写折叠,不产生任何分配、不受当前区域影响)。 /// /// 实现为经典的“双指针 + 最近星号回溯”,最坏 O(n*m),但对文件名这种短串是纳秒级。 /// public static class WildcardMatcher { public static bool IsMatch(ReadOnlySpan text, ReadOnlySpan pattern) { // ---- 快路径:绝大多数真实查询是 "*.json" / "log*" / "*tmp*" 这类“只有一个/两个通配符”的模式, // 直接退化成 EndsWith/StartsWith/IndexOf(走的是 BCL 的高度优化实现),比通用回溯快一个数量级。 int stars = 0, questions = 0, firstStar = -1, lastStar = -1; for (int i = 0; i < pattern.Length; i++) { var c = pattern[i]; if (c == '*') { stars++; if (firstStar < 0) firstStar = i; lastStar = i; } else if (c == '?') { questions++; } } if (questions == 0) { switch (stars) { case 0: return text.Equals(pattern, StringComparison.OrdinalIgnoreCase); case 1 when firstStar == 0: return text.EndsWith(pattern[1..], StringComparison.OrdinalIgnoreCase); case 1 when firstStar == pattern.Length - 1: return text.StartsWith(pattern[..^1], StringComparison.OrdinalIgnoreCase); case 2 when firstStar == 0 && lastStar == pattern.Length - 1: return text.IndexOf(pattern[1..^1], StringComparison.OrdinalIgnoreCase) >= 0; } } // ---- 通用路径:双指针 + 最近星号回溯 ---- int t = 0, p = 0; int starPattern = -1; int starText = 0; while (t < text.Length) { if (p < pattern.Length && (pattern[p] == '?' || FoldEquals(pattern[p], text[t]))) { t++; p++; } else if (p < pattern.Length && pattern[p] == '*') { // 记下最近的星号位置,先当它匹配空串继续往前走 starPattern = p++; starText = t; } else if (starPattern >= 0) { // 回溯:让最近的星号多吃一个字符 p = starPattern + 1; t = ++starText; } else { return false; } } while (p < pattern.Length && pattern[p] == '*') p++; return p == pattern.Length; } /// 是否包含通配符。 public static bool HasWildcard(ReadOnlySpan pattern) => pattern.IndexOfAny('*', '?') >= 0; /// /// 返回模式开头连续的字面量前缀(遇到 * 或 ? 为止),用于给通配符命中排优先级。 /// public static ReadOnlySpan LiteralPrefix(ReadOnlySpan pattern) { int i = 0; while (i < pattern.Length && pattern[i] is not ('*' or '?')) i++; return pattern[..i]; } /// 区域无关的大小写折叠比较(只处理 ASCII 与 BMP 常见情形,足够文件名使用)。 internal static bool FoldEquals(char a, char b) => a == b || char.ToUpperInvariant(a) == char.ToUpperInvariant(b); /// 模式里是否只剩星号(即 "*" 或 "**" 这类恒真模式)。 internal static bool IsMatchAll(ReadOnlySpan pattern) { foreach (var c in pattern) { if (c != '*') return false; } return true; } }