为什么这个正则表达式贪婪?

时间:2009-11-14 15:01:35

标签: c# regex non-greedy

我正在尝试提取“/”中包含/ thumb /的所有链接。其实我只需要使用图像src。我不知道图像是以jpg结尾还是会出现区分大小写等问题。我真的只关心完整的链接。

m = Regex.Match(page, @"""(.+?/thumbs/.+?)""");
//...
var thumbUrl = m.Groups[1].Value;

我的完整代码

    var page = DownloadWebPage(url);
    var reg = new Regex(@"Elements\s+\((.*)\)", RegexOptions.Multiline);
    var m = reg.Match(page);
    var szEleCount= m.Groups[1].Value;
    int eleCount = int.Parse(szEleCount);

    m = Regex.Match(page, @"""(.+?/thumbs/.+?)""");
    while (m.Success)
    {
        var thumbUrl = m.Groups[1].Value;
        //i break here to see a problem
        m = m.NextMatch();
    }

thumbUrl看起来像

center \“> ...很多文字,没有/ thumbs / ... src = \”http://images.fdhkdhfkd.com/thumbs/dfljdkl/22350.jpg

5 个答案:

答案 0 :(得分:4)

Nongreedy正则表达式可能很慢,因为引擎必须进行大量的回溯。

这个只使用贪婪的表达式:

@"""([^""]*/thumbs/[^""]*)"""

不是匹配最少量的东西,而是匹配尽可能多的非双引号。

答案 1 :(得分:3)

如果要解析(X)HTML,请考虑使用正确的解析器。

有关如何执行此操作的一些C#示例,请参阅:What is the best way to parse html in C#?

答案 2 :(得分:3)

一个不情愿(非贪婪)量词的工作方式是,一旦它开始匹配,它就会在第一次机会停止。你要做的是匹配符合你标准的最小文本量,这不是一回事;你仍然需要确保它没有开始匹配才能得到它。正如其他人所建议的那样,您可以将正则表达式中的.+?替换为与引号不匹配的内容,例如[^""]+

但这仍然会给您带来性能问题。在您的示例中,正则表达式在center">中看到引号时开始匹配;当它达到src="的引用时(假设您已将.+?更改为[^""]+),它将中止该匹配尝试继续前进。从src="中的引用开始的下一次尝试将成功。所以你现在得到了正确的结果,但你仍然在第一次失败的比赛尝试上浪费了很多时间。

编写快速正则表达式的关键是确保如果匹配尝试失败,它将尽快失败。例如,我认为可以安全地假设您不希望在"/thumbs/之间使用任何尖括号,因此将它们添加到您不想匹配的字符集中:{{1 }}。现在,从[^""<>]+中的引号开始的任何匹配尝试都将在下一个位置中止。

您可以采取其他措施来进一步优化正则表达式,包括原子组和负向前瞻,但这可能会根据您的需要尽快:

center">

答案 3 :(得分:1)

问题在于。+?也消耗“s,所以它继续在src属性之外匹配。请改用:

m = Regex.Match(page, @"""([^""]+/thumbs/[^""]+)""");

答案 4 :(得分:0)

通常当你有正则表达式时,你使用静态字段并指定RegexOptions.Compiled选项:

static Regex template = new Regex(@"""(.+?/thumbs/.+?)""", RegexOptions.Compiled | RegexOptions.Multiline)