需要使用Regex对字符串执行通配符(*,?等)搜索

Sco*_*ott 59 .net c# regex string wildcard

我需要在字符串上执行Wildcard(*,?等)搜索.这就是我所做的:

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");
}
Run Code Online (Sandbox Code Playgroud)

使用上面的代码"发现"块正在击中,但实际上它不应该!

如果我的模式是"e*"那么只有"找到"应该命中.

我的理解或要求是d*search应该找到包含"d"的文本,后跟任何字符.

我应该将模式更改为"d.*"和"e.*"吗?在使用Regex类时,是否支持.NET for Wild Card?

Gab*_*abe 115

来自http://www.codeproject.com/KB/recipes/wildcardtoregex.aspx:

public static string WildcardToRegex(string pattern)
{
    return "^" + Regex.Escape(pattern)
                      .Replace(@"\*", ".*")
                      .Replace(@"\?", ".")
               + "$";
}
Run Code Online (Sandbox Code Playgroud)

所以类似的东西foo*.xls?会变成^foo.*\.xls.$.

  • @dbkk代码首先调用Regex.Escape,因此它将匹配您的示例. (8认同)
  • 我认为如果在通配符模式中允许转义,这里会出现问题,例如,如果你想匹配`*`字符,那么通配符模式就是`\*`.这将转换为正则表达式`\\.*`,它做了不同的事情. (6认同)
  • 一个主要的问题是,这不会逃避其他正则表达式的特殊字符,所以像"a + .b*"(有效的文件名)这样的东西会不正确地匹配. (3认同)

Ada*_*abo 21

您可以使用名为LikeString的Visual Basic函数在没有RegEx的情况下执行简单的通配符.

using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;

if (Operators.LikeString("This is just a test", "*just*", CompareMethod.Text))
{
  Console.WriteLine("This matched!");
}
Run Code Online (Sandbox Code Playgroud)

如果你使用CompareMethod.Text它将比较不区分大小写.对于区分大小写的比较,您可以使用CompareMethod.Binary.

更多信息: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

  • 您需要添加对"Microsoft.VisualBasic"的引用 (2认同)

Mar*_*ata 10

glob表达式的正确正则表达式d*^d,匹配任何以d.开头的东西.

    string input = "Message";
    string pattern = @"^d";
    Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
Run Code Online (Sandbox Code Playgroud)

(@在这种情况下引用不是必需的,但是很好的做法,因为许多正则表达式使用反斜杠转义,需要单独留下,并且它还向读者表明此字符串是特殊的).


dee*_*hao 7

Windows和*nux以不同方式处理通配符.*,?并且.由Windows以非常复杂的方式处理,一个人的存在或位置会改变另一个人的意思.虽然*nux保持简单,但它只是一个简单的模式匹配.除此之外,Windows匹配?0或1个字符,Linux匹配恰好1个字符.

我没找到权威的文件在这个问题上,这里是基于测试天在Windows 8/XP只是我的结论(命令行dir命令要具体,和Directory.GetFiles方法使用相同的规则太)和Ubuntu服务器12.04.1 (ls命令).我做了几十个常见和不常见的案例,虽然也有很多失败的案例.

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);
    }
Run Code Online (Sandbox Code Playgroud)

有一件有趣的事情,即使Windows API PathMatchSpec也不同意FindFirstFile.只是尝试a1*.,FindFirstFile说它匹配a1,PathMatchSpec说没有.


And*_*rin 5

d*意味着它应该匹配零个或多个“ d”字符。所以任何字符串都是有效的匹配。试试d+吧!

为了支持通配符模式,我将用 RegEx 等效项替换通配符。喜欢*变成.*?变成.?。那么你上面的表达式就变成了d.*

  • +1是唯一一个解释为什么“d*”给OP带来意想不到的结果的人。但有两个问题:(1)正则表达式“d.*”不等于简单的“d”吗?(2) 通配符“d*”表示输入应以“d”开头,而正则表达式“d.*”允许“d”出现在输入的任何位置。 (2认同)