用通配符匹配字符串


71

我想用通配符(*)匹配字符串,其中通配符表示“ any”。例如:

*X = string must end with X
X* = string must start with X
*X* = string must contain X

另外,一些复合用途例如:

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

有一个简单的算法可以做到这一点吗?我不确定使用正则表达式(尽管有可能)。

为了清楚起见,用户将在上面的过滤器框中键入内容(尽可能简单的过滤器),我不希望他们自己编写正则表达式。因此,我可以轻松地从上述表示形式进行转换将是一件好事。


应该YZ ABC X匹配*X*YZ*,即子字符串是否需要以相同的顺序出现在字符串和模式中?我以为它不应该匹配,但是“字符串包含X且包含YZ”并不清楚。如果应该匹配,则当前所有答案都是错误的。
伯恩哈德·巴克

那不是。在给出的示例中,X必须出现在YZ之前。
罗宾逊

Answers:


31

仅供参考,您可以使用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);  

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

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


嗯,加上“使用”的结果是:Type or namespace name 'CompilerServices' does not exist in namespace 'Microsoft.VisualBasic' (are you missing an assembly reference?
dylanh724

3
您需要添加对Microsoft.VisualBasic.dll的引用:stackoverflow.com/a/21212268/284240
Tim Schmelter,

1
似乎在.Net 4.6中不再可用。:(
安德鲁·朗多

1
我正在使用4.7,它工作正常。该网站上有一条注释说,虽然.NET Core和.NET Standard项目不支持它。
VoteCoffee

2
现在,.NET Core 3.0版及更高版本支持它:docs.microsoft.com/en-us/dotnet/api/…–
Holf

144

通配符通常与两种玩笑者一起使用:

  ? - any character  (one and only one)
  * - any characters (zero or more)

因此,您可以轻松地将这些规则转换为适当的正则表达式

  // 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("\\*", ".*") + "$"; 
  }

然后您可以照常使用Regex

  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"));

3
很好的解决方案!
柴郡猫

这并不像您声称的那么容易。例如,一种特长是使用时Directory.GetFiles,三个字母扩展名.htm也将匹配.html,而两个字母扩展.ai名将不匹配aixaifg。Windows通配符乍一看并不容易,但是在幕后,它们是一堆增长的旧式超复杂规则集。
塞巴斯蒂安·马赫

6
@Sebastian Mach:谢谢您提到细微差别!我同意通配符的MS DOS(和Windows)解释与标准的en.wikipedia.org/wiki/Wildcard_character有所不同。但是,问题是关于字符串的,它没有提到文件。这就是为什么我将最简单的解决方案假定*为任意字符(零个或多个)并且?正好是一个字符的原因。
德米特里·拜琴科

1
最初的问题是针对字符串标识符,而不是文件系统。
罗宾逊

8
如果您担心性能,这是通配符匹配算法的C#实现,它比RegEx快得多,可以解决此特定问题。
丹·丹

19

使用WildcardPatternfromSystem.Management.Automation可能是一个选择。

pattern = new WildcardPattern(patternString);
pattern.IsMatch(stringToMatch);

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


6

通配符*可以转换为as.*.*?regex模式。

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

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

X* = > @"X(?s:.*)"
*X = > @"(?s:.*)X"
*X* = > @"(?s).*X.*"
*X*YZ* = > @"(?s).*X.*YZ.*"
X*YZ*P = > @"(?s:X.*YZ.*P)"

它们并非在每种情况下都是等效的。例如,一个Windows通配符*.htm也将匹配*.html
塞巴斯蒂安·马赫

5

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

@".*X.*YZ"

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

@"^X.*YZ.*P$"

好的,所以使用正则表达式没有什么可以简单地用*代替以获得我想要的?这些查询将由用户运行,我不希望他们理解正则表达式。
罗宾逊

是的,但是您需要指定起点和终点。^开始,$结束
Avinash Raj 2015年

好的,谢谢阿维纳什。只需将*替换为。*即可作为正则表达式。
罗宾逊

1
这个答案确实需要更多的解释。
Jerther '18

5

有必要考虑到,当检查与Y *的匹配时,Regex IsMatch对XYZ给出true。为了避免这种情况,我使用“ ^”锚点

isMatch(str1, "^" + str2.Replace("*", ".*?"));  

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

    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;
    }

2
欢迎使用Stack Overflow!尽管您可能已经解决了提问者的问题,但是仅代码答案对遇到此问题的其他人不是很有帮助。请编辑您的答案以解释您的代码为何能解决原始问题。
乔C

该解决方案将工作,如果你只是简单的匹配alpanumeric字符和其他几个人,但如果你试图匹配定义正则表达式的语法,例如任何其它字符它会失败,“ / ”或“ [ ”仅举几个例子。
jimmyfever

-3

C#控制台应用程序示例

命令行示例:
C:/> App_Exe -Opy PythonFile.py 1 2 3
控制台输出:
参数列表:-Opy PythonFile.py 1 2 3
找到python文件名:PythonFile.py

using System;
using System.Text.RegularExpressions;           //Regex

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            string cmdLine = String.Join(" ", args);

            bool bFileExtFlag = false;
            int argIndex = 0;
            Regex regex;
            foreach (string s in args)
            {
                //Search for the 1st occurrence of the "*.py" pattern
                regex = new Regex(@"(?s:.*)\056py", RegexOptions.IgnoreCase);
                bFileExtFlag = regex.IsMatch(s);
                if (bFileExtFlag == true)
                    break;
                argIndex++;
            };

            Console.WriteLine("Argument list: " + cmdLine);
            if (bFileExtFlag == true)
                Console.WriteLine("Found python filename: " + args[argIndex]);
            else
                Console.WriteLine("Python file with extension <.py> not found!");
        }


    }
}

那么您可以解决外部应用程序的问题吗?您知道浪费了多少不需要的资源吗?
NucS

@NucS我认为我们应该分析代码并找出有用的东西。无论如何,我看不到这带来了其他答案。
Jerther '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.