C# .NET 中的 glob 模式匹配
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/188892/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
glob pattern matching in .NET
提问by dmo
Is there a built-in mechanism in .NET to match patterns other than Regular Expressions? I'd like to match using UNIX style (glob) wildcards (* = any number of any character).
.NET 中是否有内置机制来匹配正则表达式以外的模式?我想使用 UNIX 样式(glob)通配符(* = 任意数量的任意字符)进行匹配。
I'd like to use this for a end-user facing control. I fear that permitting all RegEx capabilities will be very confusing.
我想将它用于面向最终用户的控件。我担心允许所有 RegEx 功能会非常混乱。
采纳答案by Jonathan C Dickinson
I found the actual code for you:
我为您找到了实际代码:
Regex.Escape( wildcardExpression ).Replace( @"\*", ".*" ).Replace( @"\?", "." );
回答by Ferruccio
I don't know if the .NET framework has glob matching, but couldn't you replace the * with .*? and use regexes?
我不知道 .NET 框架是否有 glob 匹配,但你不能用 .* 替换 * 吗?并使用正则表达式?
回答by torial
If you use VB.Net, you can use the Like statement, which has Glob like syntax.
如果您使用 VB.Net,您可以使用 Like 语句,它具有类似 Glob 的语法。
回答by Cheeso
I wrote a FileSelectorclass that does selection of files based on filenames. It also selects files based on time, size, and attributes. If you just want filename globbing then you express the name in forms like "*.txt" and similar. If you want the other parameters then you specify a boolean logic statement like "name = *.xls and ctime < 2009-01-01" - implying an .xls file created before January 1st 2009. You can also select based on the negative: "name != *.xls" means all files that are not xls.
我写了一个FileSelector类,它根据文件名选择文件。它还根据时间、大小和属性选择文件。如果您只想要文件名通配符,那么您可以以“*.txt”等形式表达名称。如果你想要其他参数,那么你指定一个布尔逻辑语句,比如“name = *.xls and ctime < 2009-01-01”——暗示在 2009 年 1 月 1 日之前创建的 .xls 文件。你也可以根据否定进行选择: “name != *.xls”表示所有不是 xls 的文件。
Check it out. Open source. Liberal license. Free to use elsewhere.
一探究竟。开源。自由许可证。在别处免费使用。
回答by Doug Clutter
Based on previous posts, I threw together a C# class:
根据以前的帖子,我拼凑了一个 C# 类:
using System;
using System.Text.RegularExpressions;
public class FileWildcard
{
Regex mRegex;
public FileWildcard(string wildcard)
{
string pattern = string.Format("^{0}$", Regex.Escape(wildcard)
.Replace(@"\*", ".*").Replace(@"\?", "."));
mRegex = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);
}
public bool IsMatch(string filenameToCompare)
{
return mRegex.IsMatch(filenameToCompare);
}
}
Using it would go something like this:
使用它会是这样的:
FileWildcard w = new FileWildcard("*.txt");
if (w.IsMatch("Doug.Txt"))
Console.WriteLine("We have a match");
The matching is NOT the same as the System.IO.Directory.GetFiles() method, so don't use them together.
匹配与 System.IO.Directory.GetFiles() 方法不同,因此不要将它们一起使用。
回答by Dan Mangiarelli
The 2- and 3-argument variants of the listing methods like GetFiles()
and EnumerateDirectories()
take a search string as their second argument that supports filename globbing, with both *
and ?
.
列表方法的 2 和 3 参数变体像GetFiles()
和EnumerateDirectories()
将搜索字符串作为支持文件名通配符的第二个参数,同时带有*
和?
。
class GlobTestMain
{
static void Main(string[] args)
{
string[] exes = Directory.GetFiles(Environment.CurrentDirectory, "*.exe");
foreach (string file in exes)
{
Console.WriteLine(Path.GetFileName(file));
}
}
}
would yield
会屈服
GlobTest.exe
GlobTest.vshost.exe
The docsstate that there are some caveats with matching extensions. It also states that 8.3 file names are matched (which may be generated automatically behind the scenes), which can result in "duplicate" matches in given some patterns.
文档指出,有一些带有匹配扩展名的警告。它还指出匹配 8.3 文件名(可能在幕后自动生成),这可能导致在给定的某些模式中出现“重复”匹配。
The methods that support this are GetFiles()
, GetDirectories()
, and GetFileSystemEntries()
. The Enumerate
variants also support this.
支持此方法是GetFiles()
,GetDirectories()
和GetFileSystemEntries()
。该Enumerate
变种也支持这一点。
回答by mindplay.dk
I like my code a little more semantic, so I wrote this extension method:
我喜欢我的代码多一点语义,所以我写了这个扩展方法:
using System.Text.RegularExpressions;
namespace Whatever
{
public static class StringExtensions
{
/// <summary>
/// Compares the string against a given pattern.
/// </summary>
/// <param name="str">The string.</param>
/// <param name="pattern">The pattern to match, where "*" means any sequence of characters, and "?" means any single character.</param>
/// <returns><c>true</c> if the string matches the given pattern; otherwise <c>false</c>.</returns>
public static bool Like(this string str, string pattern)
{
return new Regex(
"^" + Regex.Escape(pattern).Replace(@"\*", ".*").Replace(@"\?", ".") + "$",
RegexOptions.IgnoreCase | RegexOptions.Singleline
).IsMatch(str);
}
}
}
(change the namespace and/or copy the extension method to your own string extensions class)
(更改命名空间和/或将扩展方法复制到您自己的字符串扩展类)
Using this extension, you can write statements like this:
使用此扩展,您可以编写如下语句:
if (File.Name.Like("*.jpg"))
{
....
}
Just sugar to make your code a little more legible :-)
只是为了让你的代码更清晰一点:-)
回答by Tony Edgecombe
If you want to avoid regular expressions this is a basic glob implementation:
如果你想避免正则表达式,这是一个基本的 glob 实现:
public static class Globber
{
public static bool Glob(this string value, string pattern)
{
int pos = 0;
while (pattern.Length != pos)
{
switch (pattern[pos])
{
case '?':
break;
case '*':
for (int i = value.Length; i >= pos; i--)
{
if (Glob(value.Substring(i), pattern.Substring(pos + 1)))
{
return true;
}
}
return false;
default:
if (value.Length == pos || char.ToUpper(pattern[pos]) != char.ToUpper(value[pos]))
{
return false;
}
break;
}
pos++;
}
return value.Length == pos;
}
}
Use it like this:
像这样使用它:
Assert.IsTrue("text.txt".Glob("*.txt"));
回答by cleftheris
Just for the sake of completeness. Since 2016 in dotnet core
there is a new nuget package called Microsoft.Extensions.FileSystemGlobbing
that supports advanced globing paths. (Nuget Package)
只是为了完整性。自 2016 年以来,dotnet core
有一个名为Microsoft.Extensions.FileSystemGlobbing
支持高级全局路径的新 nuget 包。(Nuget 包)
some examples might be, searching for wildcard nested folder structures and files which is very common in web development scenarios.
一些示例可能是,搜索通配符嵌套文件夹结构和文件,这在 Web 开发场景中非常常见。
wwwroot/app/**/*.module.js
wwwroot/app/**/*.js
wwwroot/app/**/*.module.js
wwwroot/app/**/*.js
This works somewhat similar with what .gitignore
files use to determine which files to exclude from source control.
这与.gitignore
用于确定从源代码管理中排除哪些文件的文件有些相似。
回答by Bill Menees
From C# you can use .NET's LikeOperator.LikeStringmethod. That's the backing implementation for VB's LIKE operator. It supports patterns using *, ?, #, [charlist], and [!charlist].
在 C# 中,您可以使用 .NET 的LikeOperator.LikeString方法。这是 VB 的LIKE 运算符的支持实现。它支持使用 *、?、#、[charlist] 和 [!charlist] 的模式。
You can use the LikeString method from C# by adding a reference to the Microsoft.VisualBasic.dll assembly, which is included with every version of the .NET Framework. Then you invoke the LikeString method just like any other static .NET method:
您可以通过添加对 Microsoft.VisualBasic.dll 程序集的引用来使用 C# 中的 LikeString 方法,该程序集包含在 .NET Framework 的每个版本中。然后,您可以像调用任何其他静态 .NET 方法一样调用 LikeString 方法:
using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;
...
bool isMatch = LikeOperator.LikeString("I love .NET!", "I love *", CompareMethod.Text);
// isMatch should be true.