C# 如何在C中实现glob#

C# 如何在C中实现glob#,c#,glob,wildcard,C#,Glob,Wildcard,我不知道在StackOverflow发布您自己的问题答案是否合法,但我发现还没有人问过这个问题。我去寻找一个C#Glob,但没有找到,所以我写了一个其他人可能会觉得有用的 /// <summary> /// return a list of files that matches some wildcard pattern, e.g. /// C:\p4\software\dotnet\tools\*\*.sln to get all tool solutio

我不知道在StackOverflow发布您自己的问题答案是否合法,但我发现还没有人问过这个问题。我去寻找一个C#Glob,但没有找到,所以我写了一个其他人可能会觉得有用的
    /// <summary>
    /// return a list of files that matches some wildcard pattern, e.g. 
    /// C:\p4\software\dotnet\tools\*\*.sln to get all tool solution files
    /// </summary>
    /// <param name="glob">pattern to match</param>
    /// <returns>all matching paths</returns>
    public static IEnumerable<string> Glob(string glob)
    {
        foreach (string path in Glob(PathHead(glob) + DirSep, PathTail(glob)))
            yield return path;
    }

    /// <summary>
    /// uses 'head' and 'tail' -- 'head' has already been pattern-expanded
    /// and 'tail' has not.
    /// </summary>
    /// <param name="head">wildcard-expanded</param>
    /// <param name="tail">not yet wildcard-expanded</param>
    /// <returns></returns>
    public static IEnumerable<string> Glob(string head, string tail)
    {
        if (PathTail(tail) == tail)
            foreach (string path in Directory.GetFiles(head, tail).OrderBy(s => s))
                yield return path;
        else
            foreach (string dir in Directory.GetDirectories(head, PathHead(tail)).OrderBy(s => s))
                foreach (string path in Glob(Path.Combine(head, dir), PathTail(tail)))
                    yield return path;
    }

    /// <summary>
    /// shortcut
    /// </summary>
    static char DirSep = Path.DirectorySeparatorChar;

    /// <summary>
    /// return the first element of a file path
    /// </summary>
    /// <param name="path">file path</param>
    /// <returns>first logical unit</returns>
    static string PathHead(string path)
    {
        // handle case of \\share\vol\foo\bar -- return \\share\vol as 'head'
        // because the dir stuff won't let you interrogate a server for its share list
        // FIXME check behavior on Linux to see if this blows up -- I don't think so
        if (path.StartsWith("" + DirSep + DirSep))
            return path.Substring(0, 2) + path.Substring(2).Split(DirSep)[0] + DirSep + path.Substring(2).Split(DirSep)[1];

        return path.Split(DirSep)[0];
    }

    /// <summary>
    /// return everything but the first element of a file path
    /// e.g. PathTail("C:\TEMP\foo.txt") = "TEMP\foo.txt"
    /// </summary>
    /// <param name="path">file path</param>
    /// <returns>all but the first logical unit</returns>
    static string PathTail(string path)
    {
        if (!path.Contains(DirSep))
            return path;

        return path.Substring(1 + PathHead(path).Length);
    }
///返回与某些通配符模式匹配的文件列表,例如。 ///C:\p4\software\dotnet\tools\*\*.sln以获取所有工具解决方案文件 /// ///模式匹配 ///所有匹配路径 公共静态IEnumerable全局变量(字符串全局变量) { foreach(全局中的字符串路径(路径头(全局)+DirSep,路径尾(全局))) 收益返回路径; } /// ///使用“head”和“tail”--“head”已被模式扩展 ///而“尾巴”却没有。 /// ///通配符扩展 ///尚未扩展通配符 /// 公共静态IEnumerable Glob(字符串头、字符串尾) { if(路径尾(尾)=尾) foreach(Directory.GetFiles(head,tail.OrderBy(s=>s))中的字符串路径) 收益返回路径; 其他的 foreach(Directory.GetDirectories(head,PathHead(tail)).OrderBy(s=>s))中的字符串dir foreach(全局中的字符串路径(path.Combine(head,dir),PathTail(tail))) 收益返回路径; } /// ///捷径 /// 静态char DirSep=Path.directoryseportorchar; /// ///返回文件路径的第一个元素 /// ///文件路径 ///第一逻辑单元 静态字符串路径头(字符串路径) { //处理\\share\vol\foo\bar的大小写--将\\share\vol作为'head'返回 //因为dir文件不允许你查询服务器的共享列表 //FIXME检查Linux上的行为,看看这是否会崩溃——我不这么认为 if(路径StartsWith(“+DirSep+DirSep)) 返回path.Substring(0,2)+path.Substring(2).Split(DirSep)[0]+DirSep+path.Substring(2).Split(DirSep)[1]; 返回路径分割(DirSep)[0]; } /// ///返回除文件路径的第一个元素以外的所有内容 ///例如,路径尾(“C:\TEMP\foo.txt”)=“TEMP\foo.txt” /// ///文件路径 ///除第一个逻辑单元外的所有逻辑单元 静态字符串路径尾(字符串路径) { 如果(!path.Contains(DirSep)) 返回路径; 返回path.Substring(1+路径头(path.Length)); }
我偶然发现了iron ruby的源代码,它包含一个非常整洁的Glob类。从相关代码中提取它相当容易

您可以从C#使用“dir”(又名“Get ChildItem”)powershell cmdlet。
(我不是说你是否应该。)

您必须手动将此引用添加到项目文件(“.csproj”或“.vcproj”):

<Reference Include="System.Management.Automation" />

有关如何从C#使用cmdlet的更多详细信息,请参见此处:

这里有一个工作程序:

using System;
using System.Collections.Generic;

using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Collections.ObjectModel;

namespace CsWildcard {
    class Program {

        static IEnumerable<string> CmdletDirGlobbing(string basePath, string glob){
            Runspace runspace = RunspaceFactory.CreateRunspace();
            runspace.Open();

            // cd to basePath
            if(basePath != null){
                Pipeline cdPipeline = runspace.CreatePipeline();
                Command cdCommand = new Command("cd");
                cdCommand.Parameters.Add("Path", basePath);
                cdPipeline.Commands.Add(cdCommand);
                cdPipeline.Invoke(); // run the cmdlet
            }

            // run the "dir" cmdlet (e.g. "dir C:\*\*\*.txt" )
            Pipeline dirPipeline = runspace.CreatePipeline();
            Command dirCommand = new Command("dir");
            dirCommand.Parameters.Add("Path", glob);
            dirPipeline.Commands.Add(dirCommand);

            Collection<PSObject> dirOutput = dirPipeline.Invoke();

            // for each found file
            foreach (PSObject psObject in dirOutput) {

                PSMemberInfoCollection<PSPropertyInfo> a = psObject.Properties;
                // look for the full path ("FullName")
                foreach (PSPropertyInfo psPropertyInfo in psObject.Properties) {
                    if (psPropertyInfo.Name == "FullName") {
                        yield return psPropertyInfo.Value.ToString(); // yield it
                    }
                }
            }

        }

        static void Main(string[] args) {
            foreach(string path in CmdletDirGlobbing(null,"C:\\*\\*\\*.txt")){
                System.Console.WriteLine(path);
            }
            foreach (string path in CmdletDirGlobbing("C:\\", "*\\*\\*.exe")) {
                System.Console.WriteLine(path);
            }   
            Console.ReadKey();
        }

    }
}
使用系统;
使用System.Collections.Generic;
使用系统、管理、自动化;
使用System.Management.Automation.Runspaces;
使用System.Collections.ObjectModel;
命名空间通配符{
班级计划{
静态IEnumerable CmdletDirGlobbing(字符串基路径,字符串全局){
Runspace Runspace=RunspaceFactory.CreateRunspace();
Open();
//cd到基本路径
if(basePath!=null){
Pipeline-cdPipeline=runspace.CreatePipeline();
命令cdCommand=新命令(“cd”);
cdCommand.Parameters.Add(“路径”,basePath);
cdPipeline.Commands.Add(cdCommand);
cdPipeline.Invoke();//运行cmdlet
}
//运行“dir”cmdlet(例如“dir C:\*\*\*.txt”)
Pipeline dirPipeline=runspace.CreatePipeline();
命令dirCommand=新命令(“dir”);
dirCommand.Parameters.Add(“路径”,glob);
dirPipeline.Commands.Add(dirCommand);
集合dirOutput=dirPipeline.Invoke();
//对于每个找到的文件
foreach(直接输出中的PSObject PSObject){
PSMemberInfoCollection a=psObject.Properties;
//查找完整路径(“全名”)
foreach(PSPropertyInfo psObject.Properties中的PSPropertyInfo){
如果(psPropertyInfo.Name==“FullName”){
yield返回psPropertyInfo.Value.ToString();//yield
}
}
}
}
静态void Main(字符串[]参数){
foreach(CmdletDirGlobbing中的字符串路径(null,“C:\\*\\\*\\\\\*.txt”)){
System.Console.WriteLine(路径);
}
foreach(CmdletDirGlobbing(“C:\\”,“*\\\*\\\*.exe”)中的字符串路径){
System.Console.WriteLine(路径);
}   
Console.ReadKey();
}
}
}
使用以下工具很容易:

例如:

公共静态类Glob
{
公共静态IEnumerable Exec(目录信息目录,字符串全局)
{
var matcher=DotNet.Globbing.Glob.Parse(Glob);
return dir.EnumerateAllFiles().Where(f=>matcher.IsMatch(f.FullName));
}
公共静态IEnumerable EnumerateAllFiles(此目录信息目录)
{
foreach(dir.EnumerateFiles()中的var f)
{
收益率f;
}
foreach(目录枚举目录()中的var sub)
{
foreach(枚举所有文件(子文件)中的变量f)
{
收益率f;
}
}
}
}

通过谷歌搜索,我找到了glob应该做什么。如果不是将其作为社区维基,您会得到更多分数。:-)为什么我会得到更多的分数?我是新来的…仅供参考:地球看起来像路径***。txt@Mark因为社区维基的答案不会给你分数,每次投票通常会给你10分?我不得不将“Path.Combine(head,dir)”替换为“dir”,因为Directory.GetDirectories已经返回完整路径。这导致了一个像“.\SomeDir*.dll”这样的路径的错误,因为“.\”是由Combine复制的。这似乎不正确