Initial commit: FluidExplorer:从零实现的 WinUI 3 文件资源管理器替代品(Mica、命令栏、面包屑)

This commit is contained in:
WpyQwq
2026-09-19 11:54:03 +08:00
commit 5780fde61a
60 changed files with 15035 additions and 0 deletions
+107
View File
@@ -0,0 +1,107 @@
namespace FluidExplorer.Services.Search.Usn;
/// <summary>
/// 通配符匹配器:<c>?</c> 匹配任意单字符,<c>*</c> 匹配任意长度(含空),
/// 大小写不敏感(用固定区域的大小写折叠,不产生任何分配、不受当前区域影响)。
///
/// 实现为经典的“双指针 + 最近星号回溯”,最坏 O(n*m),但对文件名这种短串是纳秒级。
/// </summary>
public static class WildcardMatcher
{
public static bool IsMatch(ReadOnlySpan<char> text, ReadOnlySpan<char> 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;
}
/// <summary>是否包含通配符。</summary>
public static bool HasWildcard(ReadOnlySpan<char> pattern) =>
pattern.IndexOfAny('*', '?') >= 0;
/// <summary>
/// 返回模式开头连续的字面量前缀(遇到 * 或 ? 为止),用于给通配符命中排优先级。
/// </summary>
public static ReadOnlySpan<char> LiteralPrefix(ReadOnlySpan<char> pattern)
{
int i = 0;
while (i < pattern.Length && pattern[i] is not ('*' or '?')) i++;
return pattern[..i];
}
/// <summary>区域无关的大小写折叠比较(只处理 ASCII 与 BMP 常见情形,足够文件名使用)。</summary>
internal static bool FoldEquals(char a, char b) =>
a == b || char.ToUpperInvariant(a) == char.ToUpperInvariant(b);
/// <summary>模式里是否只剩星号(即 "*" 或 "**" 这类恒真模式)。</summary>
internal static bool IsMatchAll(ReadOnlySpan<char> pattern)
{
foreach (var c in pattern)
{
if (c != '*') return false;
}
return true;
}
}