C#如何优雅实现匹配多层通配符的目录枚举
多段路径通配符匹配目录问题
我的文件夹结构如下:
c:\logs\v1\api1 c:\logs\v1\api2 c:\logs\v2\api1 c:\logs\v2\api2 c:\logs\other
我需要获取匹配如下通配符模式的所有文件夹:
c:\logs\v*\api*
预期返回的目录列表为:
c:\logs\v1\api1 c:\logs\v1\api2 c:\logs\v2\api1 c:\logs\v2\api2
无效实现尝试
直接传入带多层通配符的路径
以下写法无法正常运行:
var result = Directory.GetDirectories(@"c:\logs\v*\api*");
运行时抛出异常:System.IO.IOException: 'The filename, directory name, or volume label syntax is incorrect. : 'c:\logs\v*\api*''
拆分磁盘根目录后传入搜索模式
以下尝试同样无法正常运行:
var directory = @"c:\logs\v*\api*"; var rootDirectory = Directory.GetDirectoryRoot(directory); var remainingPath = directory.Substring(rootDirectory.Length); Console.WriteLine($"remainingPath: {remainingPath}"); var result = Directory.GetDirectories(rootDirectory, remainingPath);
运行时抛出异常:System.IO.IOException: 'The filename, directory name, or volume label syntax is incorrect. : 'c:\logs\v*''
可用但不够简洁的实现
递归逐段匹配实现
如下递归逐段匹配的实现可以正常生效:
public static IEnumerable<string> ResolveDirectories(string path) { if (path.Contains("*") || path.Contains("?")) { var parts = new Regex(@"[\/](?=[^\/]*[\*?])").Split(path, 2); var searchRoot = parts[0]; var searchPatterns = parts[1].Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); foreach (var dir in ResolveWildcards(searchRoot, searchPatterns)) yield return dir; } else { yield return path; } } public static IEnumerable<string> ResolveWildcards(string searchRoot, string[] searchPatterns) { if (Directory.Exists(searchRoot)) { // 取下一级匹配规则在当前目录搜索 var next = searchPatterns[0]; // 剩余匹配规则留待递归处理 var rest = searchPatterns.Skip(1).ToArray(); if (!searchRoot.EndsWith("\\")) searchRoot += "\\"; foreach (var dir in Directory.EnumerateDirectories(searchRoot, next)) { // 已经是最后一级匹配规则,直接返回结果 if (rest.Length == 0) yield return dir; else { // 非最后一级,用剩余规则在新找到的目录下继续搜索 foreach (var sub in ResolveWildcards(dir, rest)) yield return sub; } } } }
但该实现的代码写法不够简洁。
全量遍历+正则匹配实现
参考@Alessandro_D'Andria提供的思路,我实现了如下版本:
public static IEnumerable<string> ResolveDirectories(string path) { var parts = new Regex(@"[\/](?=[^\/]*[\*?])").Split(path, 2); var root = parts[0]; var part = @".*\\" + parts[1].Replace(@"\", @"\\"); var regex = new Regex(part); var dirs = Directory .EnumerateDirectories( root, "*", SearchOption.AllDirectories) .Where(x => regex.IsMatch(x)) .ToList(); return dirs; }
上述两种实现都较为繁琐,想了解是否存在更优雅的实现方案?
内容的提问来源于stack exchange,提问作者dafie
相关产品推荐
相关产品推荐

