使用通配符匹配字符串

Rob*_*son 52 c# regex string wildcard

我想匹配字符串与通配符(*),其中通配符表示"任何".例如:

*X = string must end with X
X* = string must start with X
*X* = string must contain X
Run Code Online (Sandbox Code Playgroud)

此外,一些复合用途,如:

*X*YZ* = string contains X and contains YZ
X*YZ*P = string starts with X, contains YZ and ends with P.
Run Code Online (Sandbox Code Playgroud)

有一个简单的算法来做到这一点?我不确定使用正则表达式(虽然这是一种可能性).

为了澄清,用户将在上面输入一个过滤器框(尽可能简单的过滤器),我不希望他们自己编写正则表达式.所以我可以很容易地从上面的符号转换出来的东西会很好.

Dmi*_*nko 107

通常,外卡使用两种类型的笑话:

  ? - any character  (one and only one)
  * - any characters (zero or more)
Run Code Online (Sandbox Code Playgroud)

这样您就可以轻松地将这些规则转换为适当的常规表达式:

  // If you want to implement both "*" and "?"
  private static String WildCardToRegular(String value) {
    return "^" + Regex.Escape(value).Replace("\\?", ".").Replace("\\*", ".*") + "$"; 
  }

  // If you want to implement "*" only
  private static String WildCardToRegular(String value) {
    return "^" + Regex.Escape(value).Replace("\\*", ".*") + "$"; 
  }
Run Code Online (Sandbox Code Playgroud)

然后你可以照常使用正则表达式:

  String test = "Some Data X";

  Boolean endsWithEx = Regex.IsMatch(test, WildCardToRegular("*X"));
  Boolean startsWithS = Regex.IsMatch(test, WildCardToRegular("S*"));
  Boolean containsD = Regex.IsMatch(test, WildCardToRegular("*D*"));

  // Starts with S, ends with X, contains "me" and "a" (in that order) 
  Boolean complex = Regex.IsMatch(test, WildCardToRegular("S*me*a*X"));
Run Code Online (Sandbox Code Playgroud)

  • 如果你担心性能,[这里是通配符匹配算法的C#实现](https://bitbucket.org/hasullivan/fast-wildcard-matching),这比RegEx对这个特定问题要快得多. (3认同)
  • 很好的解决方案! (2认同)
  • @Sebastian Mach:谢谢您提到细微差别!我同意“通配符”的MS DOS(和Windows)解释与标准的https://en.wikipedia.org/wiki/Wildcard_character不同。但是,问题是关于字符串的,它没有提到文件;而是有关字符串的问题。这就是为什么我提出最简单的解决方案,假设`*`是任何字符(零个或多个),而`?`正好是一个字符。 (2认同)
  • 最初的问题是针对字符串标识符,而不是文件系统,正确。 (2认同)

Tim*_*ter 22

仅供参考,您可以使用VB.NET Like-Operator:

string text = "x is not the same as X and yz not the same as YZ";
bool contains = LikeOperator.LikeString(text,"*X*YZ*", Microsoft.VisualBasic.CompareMethod.Binary);  
Run Code Online (Sandbox Code Playgroud)

使用CompareMethod.Text,如果你想忽略大小写.

你需要添加using Microsoft.VisualBasic.CompilerServices;.

  • 现在 .NET Core 3.0 版及以上版本支持它:https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualbasic.compilerservices.likeoperator.likestring?view=netcore-3.1#moniker-applies -到 (5认同)
  • 您需要添加对Microsoft.VisualBasic.dll的引用:/sf/answers/1484858791/ (3认同)

Vir*_*VDX 15

使用WildcardPatternfrom System.Management.Automation可能是一种选择.

pattern = new WildcardPattern(patternString);
pattern.IsMatch(stringToMatch);
Run Code Online (Sandbox Code Playgroud)

Visual Studio UI可能不允许您将System.Management.Automation程序集添加到项目的引用.随意手动添加,如所描述这里.


Wik*_*żew 6

通配符*可以翻译为.*.*?正则表达式。

您可能需要使用单行模式来匹配换行符,在这种情况下,您可以将其(?s)用作正则表达式模式的一部分。

您可以为整个或部分模式设置它:

X* = > @"X(?s:.*)"
*X = > @"(?s:.*)X"
*X* = > @"(?s).*X.*"
*X*YZ* = > @"(?s).*X.*YZ.*"
X*YZ*P = > @"(?s:X.*YZ.*P)"
Run Code Online (Sandbox Code Playgroud)


Jam*_*ter 6

对于使用 .NET Core 2.1+ 或 .NET 5 的用户,您可以使用System.IO.Enumeration 命名空间中的FileSystemName.MatchesSimpleExpression方法。

string text = "X is a string with ZY in the middle and at the end is P";
bool isMatch = FileSystemName.MatchesSimpleExpression("X*ZY*P", text);
Run Code Online (Sandbox Code Playgroud)

这两个参数实际上都是,ReadOnlySpan<char>但您也可以使用字符串参数。如果您想打开/关闭大小写匹配,还有一个重载方法。

  • 正是我所需要的并且工作完美。默认情况下不区分大小写。 (2认同)

Avi*_*Raj 5

*X*YZ* = string contains X and contains YZ

@".*X.*YZ"
Run Code Online (Sandbox Code Playgroud)

X*YZ*P = string starts with X, contains YZ and ends with P.

@"^X.*YZ.*P$"
Run Code Online (Sandbox Code Playgroud)

  • 这个答案确实需要更多解释。 (2认同)

Pav*_*kin 5

在检查与 Y* 的匹配时,有必要考虑到 Regex IsMatch 对 XYZ 的结果为真。为了避免它,我使用“^”锚

isMatch(str1, "^" + str2.Replace("*", ".*?"));  
Run Code Online (Sandbox Code Playgroud)

因此,解决您的问题的完整代码是

    bool isMatchStr(string str1, string str2)
    {
        string s1 = str1.Replace("*", ".*?");
        string s2 = str2.Replace("*", ".*?");
        bool r1 = Regex.IsMatch(s1, "^" + s2);
        bool r2 = Regex.IsMatch(s2, "^" + s1);
        return r1 || r2;
    }
Run Code Online (Sandbox Code Playgroud)

  • 欢迎使用堆栈溢出!虽然您可能已经解决了提问者的问题,但只有代码的答案对遇到此问题的其他人并没有太大帮助。请编辑您的答案以解释为什么您的代码解决了原始问题。 (2认同)