I need to perform Wildcard (*
, ?
, etc.) search on a string. This is what I have done:
我需要执行通配符(*,?,等等)搜索字符串。这就是我所做的:
string input = "Message";
string pattern = "d*";
Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
if (regex.IsMatch(input))
{
MessageBox.Show("Found");
}
else
{
MessageBox.Show("Not Found");
}
With the above code "Found" block is hitting but actually it should not!
使用上述代码“发现”块正在打击,但实际上它不应该!
If my pattern is "e*" then only "Found" should hit.
如果我的模式是“e*”,那么只有“发现”应该被击中。
My understanding or requirement is d* search should find the text containing "d" followed by any characters.
我的理解或要求是d* search应该找到包含“d”的文本,后面跟着任何字符。
Should I change my pattern as "d.*" and "e.*"? Is there any support in .NET for Wild Card which internally does it while using Regex class?
我应该把模式改成d吗?*”和“e。*”?在。net中是否有对外卡的支持,它是在内部使用Regex类的时候使用的?
10 个解决方案
#1
113
From http://www.codeproject.com/KB/recipes/wildcardtoregex.aspx:
从http://www.codeproject.com/KB/recipes/wildcardtoregex.aspx:
public static string WildcardToRegex(string pattern)
{
return "^" + Regex.Escape(pattern)
.Replace(@"\*", ".*")
.Replace(@"\?", ".")
+ "$";
}
So something like foo*.xls?
will get transformed to ^foo.*\.xls.$
.
所以类似foo * xls ?会转化为^ foo . * \ xls,美元。
#2
21
You can do a simple wildcard mach without RegEx using a Visual Basic function called LikeString.
您可以使用一个名为LikeString的Visual Basic函数在不使用RegEx的情况下完成一个简单的通配符mach。
using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;
if (Operators.LikeString("This is just a test", "*just*", CompareMethod.Text))
{
Console.WriteLine("This matched!");
}
If you use CompareMethod.Text
it will compare case-insensitive. For case-sensitive comparison, you can use CompareMethod.Binary
.
如果你使用CompareMethod。它将比较不区分大小写的文本。对于区分大小写的比较,可以使用CompareMethod.Binary。
More info here: http://www.henrikbrinch.dk/Blog/2012/02/14/Wildcard-matching-in-C
更多信息:http://www.henrikbrinch.dk/Blog/2012/02/14/Wildcard-matching-in-C
MSDN:http://msdn.microsoft.com/en-us/library/microsoft.visualbasic.compilerservices.operators.likestring%28v=vs.100%29.ASPX
#3
10
The correct regular expression formulation of the glob expression d*
is ^d
, which means match anything that starts with d
.
通配符匹配操作符表达式的正确的正则表达式配方d * ^ d,这意味着匹配任何始于d。
string input = "Message";
string pattern = @"^d";
Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
(The @
quoting is not necessary in this case, but good practice since many regexes use backslash escapes that need to be left alone, and it also indicates to the reader that this string is special).
(在这种情况下,@引号不是必需的,但是很好的实践,因为许多regex使用了需要单独使用的反斜杠转义,而且它还向读者表明这个字符串是特殊的)。
#4
5
Windows and *nux treat wildcards differently. *
, ?
and .
are processed in a very complex way by Windows, one's presence or position would change another's meaning. While *nux keeps it simple, all it does is just one simple pattern match. Besides that, Windows matches ?
for 0 or 1 chars, Linux matches it for exactly 1 chars.
Windows和*nux对通配符的处理不同。*、?和。一个人的存在或位置会改变另一个人的意义。虽然*nux保持简单,但它所做的只是一个简单的模式匹配。除此之外,Windows还能匹配吗?对于0或1个字符,Linux恰好匹配1个字符。
I didn't find authoritative documents on this matter, here is just my conclusion based on days of tests on Windows 8/XP (command line, dir
command to be specific, and the Directory.GetFiles
method uses the same rules too) and Ubuntu Server 12.04.1 (ls
command). I made tens of common and uncommon cases work, although there'are many failed cases too.
我没有找到关于这个问题的权威文档,这里只是基于对Windows 8/XP(命令行,特定的dir命令,以及目录的测试得出的结论。GetFiles方法也使用相同的规则)和Ubuntu服务器12.04.1 (ls命令)。我做了几十个常见和不常见的案例,尽管也有很多失败的案例。
The current answer by Gabe, works like *nux. If you also want a Windows style one, and are willing to accept the imperfection, then here it is:
Gabe目前的答案是*nux。如果你也想要一个Windows风格的,并且愿意接受不完美的地方,那么它就是:
/// <summary>
/// <para>Tests if a file name matches the given wildcard pattern, uses the same rule as shell commands.</para>
/// </summary>
/// <param name="fileName">The file name to test, without folder.</param>
/// <param name="pattern">A wildcard pattern which can use char * to match any amount of characters; or char ? to match one character.</param>
/// <param name="unixStyle">If true, use the *nix style wildcard rules; otherwise use windows style rules.</param>
/// <returns>true if the file name matches the pattern, false otherwise.</returns>
public static bool MatchesWildcard(this string fileName, string pattern, bool unixStyle)
{
if (fileName == null)
throw new ArgumentNullException("fileName");
if (pattern == null)
throw new ArgumentNullException("pattern");
if (unixStyle)
return WildcardMatchesUnixStyle(pattern, fileName);
return WildcardMatchesWindowsStyle(fileName, pattern);
}
private static bool WildcardMatchesWindowsStyle(string fileName, string pattern)
{
var dotdot = pattern.IndexOf("..", StringComparison.Ordinal);
if (dotdot >= 0)
{
for (var i = dotdot; i < pattern.Length; i++)
if (pattern[i] != '.')
return false;
}
var normalized = Regex.Replace(pattern, @"\.+$", "");
var endsWithDot = normalized.Length != pattern.Length;
var endWeight = 0;
if (endsWithDot)
{
var lastNonWildcard = normalized.Length - 1;
for (; lastNonWildcard >= 0; lastNonWildcard--)
{
var c = normalized[lastNonWildcard];
if (c == '*')
endWeight += short.MaxValue;
else if (c == '?')
endWeight += 1;
else
break;
}
if (endWeight > 0)
normalized = normalized.Substring(0, lastNonWildcard + 1);
}
var endsWithWildcardDot = endWeight > 0;
var endsWithDotWildcardDot = endsWithWildcardDot && normalized.EndsWith(".");
if (endsWithDotWildcardDot)
normalized = normalized.Substring(0, normalized.Length - 1);
normalized = Regex.Replace(normalized, @"(?!^)(\.\*)+$", @".*");
var escaped = Regex.Escape(normalized);
string head, tail;
if (endsWithDotWildcardDot)
{
head = "^" + escaped;
tail = @"(\.[^.]{0," + endWeight + "})?$";
}
else if (endsWithWildcardDot)
{
head = "^" + escaped;
tail = "[^.]{0," + endWeight + "}$";
}
else
{
head = "^" + escaped;
tail = "$";
}
if (head.EndsWith(@"\.\*") && head.Length > 5)
{
head = head.Substring(0, head.Length - 4);
tail = @"(\..*)?" + tail;
}
var regex = head.Replace(@"\*", ".*").Replace(@"\?", "[^.]?") + tail;
return Regex.IsMatch(fileName, regex, RegexOptions.IgnoreCase);
}
private static bool WildcardMatchesUnixStyle(string pattern, string text)
{
var regex = "^" + Regex.Escape(pattern)
.Replace("\\*", ".*")
.Replace("\\?", ".")
+ "$";
return Regex.IsMatch(text, regex);
}
There's a funny thing, even the Windows API PathMatchSpec does not agree with FindFirstFile. Just try a1*.
, FindFirstFile
says it matches a1
, PathMatchSpec
says not.
有趣的是,即使是Windows API PathMatchSpec也与FindFirstFile不一致。试试a1 *。FindFirstFile说它匹配a1, PathMatchSpec说没有。
#5
3
d*
means that it should match zero or more "d
" characters. So any string is a valid match. Try d+
instead!
d*意味着它应该匹配零个或多个“d”字符。所以任何字符串都是有效匹配。试试d + !
In order to have support for wildcard patterns I would replace the wildcards with the RegEx equivalents. Like *
becomes .*
and ?
becomes .?
. Then your expression above becomes d.*
为了支持通配符模式,我将用RegEx等价替换通配符。像*变成。*和?变成了。。那么上面的表达式就变成了d *
#6
3
You need to convert your wildcard expression to a regular expression. For example:
您需要将通配符表达式转换为正则表达式。例如:
private bool WildcardMatch(String s, String wildcard, bool case_sensitive)
{
// Replace the * with an .* and the ? with a dot. Put ^ at the
// beginning and a $ at the end
String pattern = "^" + Regex.Escape(wildcard).Replace(@"\*", ".*").Replace(@"\?", ".") + "$";
// Now, run the Regex as you already know
Regex regex;
if(case_sensitive)
regex = new Regex(pattern);
else
regex = new Regex(pattern, RegexOptions.IgnoreCase);
return(regex.IsMatch(s));
}
#7
3
You must escape special Regex symbols in input wildcard pattern (for example pattern *.txt
will equivalent to ^.*\.txt$
) So slashes, braces and many special symbols must be replaced with @"\" + s
, where s
- special Regex symbol.
您必须在输入通配符模式(例如模式*)中转义特殊的Regex符号。txt将美元相当于^ . * \ . txt)所以斜杠,括号和许多特殊符号必须替换@ + s“\”,在s -特殊的正则表达式的符号。
#8
0
All upper code is not correct to the end.
所有上面的代码最后都不正确。
This is because when searching zz*foo* or zz* you will not get correct results.
这是因为搜索zz*foo*或zz*时不会得到正确的结果。
And if you search "abcd*" in "abcd" in TotalCommander will he find a abcd file so all upper code is wrong.
如果你在TotalCommander的“abcd”中搜索“abcd*”,他会找到abcd文件吗?
Here is the correct code.
这是正确的代码。
public string WildcardToRegex(string pattern)
{
string result= Regex.Escape(pattern).
Replace(@"\*", ".+?").
Replace(@"\?", ".");
if (result.EndsWith(".+?"))
{
result = result.Remove(result.Length - 3, 3);
result += ".*";
}
return result;
}
#9
0
You may want to use WildcardPattern
from System.Management.Automation
assembly. See my answer here.
您可能希望使用System.Management中的通配符模式。自动化装配。看到我的答案。
#10
0
I think @Dmitri has nice solution at Matching strings with wildcard https://*.com/a/30300521/1726296
我认为@Dmitri有很好的解决方案,可以将字符串与通配符https://*.com/a/30300521/1726296匹配
Based on his solution, I have created two extension methods. (credit goes to him)
基于他的解决方案,我创建了两个扩展方法。(信用去他)
May be helpful.
可能是有益的。
public static String WildCardToRegular(this String value)
{
return "^" + Regex.Escape(value).Replace("\\?", ".").Replace("\\*", ".*") + "$";
}
public static bool WildCardMatch(this String value,string pattern,bool ignoreCase = true)
{
if (ignoreCase)
return Regex.IsMatch(value, WildCardToRegular(pattern), RegexOptions.IgnoreCase);
return Regex.IsMatch(value, WildCardToRegular(pattern));
}
Usage:
用法:
string pattern = "file.*";
var isMatched = "file.doc".WildCardMatch(pattern)
or
或
string xlsxFile = "file.xlsx"
var isMatched = xlsxFile.WildCardMatch(pattern)
#1
113
From http://www.codeproject.com/KB/recipes/wildcardtoregex.aspx:
从http://www.codeproject.com/KB/recipes/wildcardtoregex.aspx:
public static string WildcardToRegex(string pattern)
{
return "^" + Regex.Escape(pattern)
.Replace(@"\*", ".*")
.Replace(@"\?", ".")
+ "$";
}
So something like foo*.xls?
will get transformed to ^foo.*\.xls.$
.
所以类似foo * xls ?会转化为^ foo . * \ xls,美元。
#2
21
You can do a simple wildcard mach without RegEx using a Visual Basic function called LikeString.
您可以使用一个名为LikeString的Visual Basic函数在不使用RegEx的情况下完成一个简单的通配符mach。
using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;
if (Operators.LikeString("This is just a test", "*just*", CompareMethod.Text))
{
Console.WriteLine("This matched!");
}
If you use CompareMethod.Text
it will compare case-insensitive. For case-sensitive comparison, you can use CompareMethod.Binary
.
如果你使用CompareMethod。它将比较不区分大小写的文本。对于区分大小写的比较,可以使用CompareMethod.Binary。
More info here: http://www.henrikbrinch.dk/Blog/2012/02/14/Wildcard-matching-in-C
更多信息:http://www.henrikbrinch.dk/Blog/2012/02/14/Wildcard-matching-in-C
MSDN:http://msdn.microsoft.com/en-us/library/microsoft.visualbasic.compilerservices.operators.likestring%28v=vs.100%29.ASPX
#3
10
The correct regular expression formulation of the glob expression d*
is ^d
, which means match anything that starts with d
.
通配符匹配操作符表达式的正确的正则表达式配方d * ^ d,这意味着匹配任何始于d。
string input = "Message";
string pattern = @"^d";
Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
(The @
quoting is not necessary in this case, but good practice since many regexes use backslash escapes that need to be left alone, and it also indicates to the reader that this string is special).
(在这种情况下,@引号不是必需的,但是很好的实践,因为许多regex使用了需要单独使用的反斜杠转义,而且它还向读者表明这个字符串是特殊的)。
#4
5
Windows and *nux treat wildcards differently. *
, ?
and .
are processed in a very complex way by Windows, one's presence or position would change another's meaning. While *nux keeps it simple, all it does is just one simple pattern match. Besides that, Windows matches ?
for 0 or 1 chars, Linux matches it for exactly 1 chars.
Windows和*nux对通配符的处理不同。*、?和。一个人的存在或位置会改变另一个人的意义。虽然*nux保持简单,但它所做的只是一个简单的模式匹配。除此之外,Windows还能匹配吗?对于0或1个字符,Linux恰好匹配1个字符。
I didn't find authoritative documents on this matter, here is just my conclusion based on days of tests on Windows 8/XP (command line, dir
command to be specific, and the Directory.GetFiles
method uses the same rules too) and Ubuntu Server 12.04.1 (ls
command). I made tens of common and uncommon cases work, although there'are many failed cases too.
我没有找到关于这个问题的权威文档,这里只是基于对Windows 8/XP(命令行,特定的dir命令,以及目录的测试得出的结论。GetFiles方法也使用相同的规则)和Ubuntu服务器12.04.1 (ls命令)。我做了几十个常见和不常见的案例,尽管也有很多失败的案例。
The current answer by Gabe, works like *nux. If you also want a Windows style one, and are willing to accept the imperfection, then here it is:
Gabe目前的答案是*nux。如果你也想要一个Windows风格的,并且愿意接受不完美的地方,那么它就是:
/// <summary>
/// <para>Tests if a file name matches the given wildcard pattern, uses the same rule as shell commands.</para>
/// </summary>
/// <param name="fileName">The file name to test, without folder.</param>
/// <param name="pattern">A wildcard pattern which can use char * to match any amount of characters; or char ? to match one character.</param>
/// <param name="unixStyle">If true, use the *nix style wildcard rules; otherwise use windows style rules.</param>
/// <returns>true if the file name matches the pattern, false otherwise.</returns>
public static bool MatchesWildcard(this string fileName, string pattern, bool unixStyle)
{
if (fileName == null)
throw new ArgumentNullException("fileName");
if (pattern == null)
throw new ArgumentNullException("pattern");
if (unixStyle)
return WildcardMatchesUnixStyle(pattern, fileName);
return WildcardMatchesWindowsStyle(fileName, pattern);
}
private static bool WildcardMatchesWindowsStyle(string fileName, string pattern)
{
var dotdot = pattern.IndexOf("..", StringComparison.Ordinal);
if (dotdot >= 0)
{
for (var i = dotdot; i < pattern.Length; i++)
if (pattern[i] != '.')
return false;
}
var normalized = Regex.Replace(pattern, @"\.+$", "");
var endsWithDot = normalized.Length != pattern.Length;
var endWeight = 0;
if (endsWithDot)
{
var lastNonWildcard = normalized.Length - 1;
for (; lastNonWildcard >= 0; lastNonWildcard--)
{
var c = normalized[lastNonWildcard];
if (c == '*')
endWeight += short.MaxValue;
else if (c == '?')
endWeight += 1;
else
break;
}
if (endWeight > 0)
normalized = normalized.Substring(0, lastNonWildcard + 1);
}
var endsWithWildcardDot = endWeight > 0;
var endsWithDotWildcardDot = endsWithWildcardDot && normalized.EndsWith(".");
if (endsWithDotWildcardDot)
normalized = normalized.Substring(0, normalized.Length - 1);
normalized = Regex.Replace(normalized, @"(?!^)(\.\*)+$", @".*");
var escaped = Regex.Escape(normalized);
string head, tail;
if (endsWithDotWildcardDot)
{
head = "^" + escaped;
tail = @"(\.[^.]{0," + endWeight + "})?$";
}
else if (endsWithWildcardDot)
{
head = "^" + escaped;
tail = "[^.]{0," + endWeight + "}$";
}
else
{
head = "^" + escaped;
tail = "$";
}
if (head.EndsWith(@"\.\*") && head.Length > 5)
{
head = head.Substring(0, head.Length - 4);
tail = @"(\..*)?" + tail;
}
var regex = head.Replace(@"\*", ".*").Replace(@"\?", "[^.]?") + tail;
return Regex.IsMatch(fileName, regex, RegexOptions.IgnoreCase);
}
private static bool WildcardMatchesUnixStyle(string pattern, string text)
{
var regex = "^" + Regex.Escape(pattern)
.Replace("\\*", ".*")
.Replace("\\?", ".")
+ "$";
return Regex.IsMatch(text, regex);
}
There's a funny thing, even the Windows API PathMatchSpec does not agree with FindFirstFile. Just try a1*.
, FindFirstFile
says it matches a1
, PathMatchSpec
says not.
有趣的是,即使是Windows API PathMatchSpec也与FindFirstFile不一致。试试a1 *。FindFirstFile说它匹配a1, PathMatchSpec说没有。
#5
3
d*
means that it should match zero or more "d
" characters. So any string is a valid match. Try d+
instead!
d*意味着它应该匹配零个或多个“d”字符。所以任何字符串都是有效匹配。试试d + !
In order to have support for wildcard patterns I would replace the wildcards with the RegEx equivalents. Like *
becomes .*
and ?
becomes .?
. Then your expression above becomes d.*
为了支持通配符模式,我将用RegEx等价替换通配符。像*变成。*和?变成了。。那么上面的表达式就变成了d *
#6
3
You need to convert your wildcard expression to a regular expression. For example:
您需要将通配符表达式转换为正则表达式。例如:
private bool WildcardMatch(String s, String wildcard, bool case_sensitive)
{
// Replace the * with an .* and the ? with a dot. Put ^ at the
// beginning and a $ at the end
String pattern = "^" + Regex.Escape(wildcard).Replace(@"\*", ".*").Replace(@"\?", ".") + "$";
// Now, run the Regex as you already know
Regex regex;
if(case_sensitive)
regex = new Regex(pattern);
else
regex = new Regex(pattern, RegexOptions.IgnoreCase);
return(regex.IsMatch(s));
}
#7
3
You must escape special Regex symbols in input wildcard pattern (for example pattern *.txt
will equivalent to ^.*\.txt$
) So slashes, braces and many special symbols must be replaced with @"\" + s
, where s
- special Regex symbol.
您必须在输入通配符模式(例如模式*)中转义特殊的Regex符号。txt将美元相当于^ . * \ . txt)所以斜杠,括号和许多特殊符号必须替换@ + s“\”,在s -特殊的正则表达式的符号。
#8
0
All upper code is not correct to the end.
所有上面的代码最后都不正确。
This is because when searching zz*foo* or zz* you will not get correct results.
这是因为搜索zz*foo*或zz*时不会得到正确的结果。
And if you search "abcd*" in "abcd" in TotalCommander will he find a abcd file so all upper code is wrong.
如果你在TotalCommander的“abcd”中搜索“abcd*”,他会找到abcd文件吗?
Here is the correct code.
这是正确的代码。
public string WildcardToRegex(string pattern)
{
string result= Regex.Escape(pattern).
Replace(@"\*", ".+?").
Replace(@"\?", ".");
if (result.EndsWith(".+?"))
{
result = result.Remove(result.Length - 3, 3);
result += ".*";
}
return result;
}
#9
0
You may want to use WildcardPattern
from System.Management.Automation
assembly. See my answer here.
您可能希望使用System.Management中的通配符模式。自动化装配。看到我的答案。
#10
0
I think @Dmitri has nice solution at Matching strings with wildcard https://*.com/a/30300521/1726296
我认为@Dmitri有很好的解决方案,可以将字符串与通配符https://*.com/a/30300521/1726296匹配
Based on his solution, I have created two extension methods. (credit goes to him)
基于他的解决方案,我创建了两个扩展方法。(信用去他)
May be helpful.
可能是有益的。
public static String WildCardToRegular(this String value)
{
return "^" + Regex.Escape(value).Replace("\\?", ".").Replace("\\*", ".*") + "$";
}
public static bool WildCardMatch(this String value,string pattern,bool ignoreCase = true)
{
if (ignoreCase)
return Regex.IsMatch(value, WildCardToRegular(pattern), RegexOptions.IgnoreCase);
return Regex.IsMatch(value, WildCardToRegular(pattern));
}
Usage:
用法:
string pattern = "file.*";
var isMatched = "file.doc".WildCardMatch(pattern)
or
或
string xlsxFile = "file.xlsx"
var isMatched = xlsxFile.WildCardMatch(pattern)