【问题标题】:Why is this regex being greedy?为什么这个正则表达式很贪婪?
【发布时间】:2009-11-14 15:01:34
【问题描述】:

我正在尝试提取“”中包含 /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

【问题讨论】:

  • 仅供参考,Multiline 选项对您没有任何帮助。如果您希望点与行分隔符匹配,则应改用 Singleline

标签: c# regex non-greedy


【解决方案1】:

非贪婪的正则表达式可能会很慢,因为引擎必须执行大量回溯。

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

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

它匹配尽可能多的非双引号,而不是匹配任何内容。

【讨论】:

    【解决方案2】:

    勉强(非贪婪)量词的工作方式是,一旦开始匹配,它就会一有机会就停止。您要做的是匹配符合您标准的最少文本数量,这不是一回事;您仍然必须确保它不会在您想要它之前 start 匹配。正如其他人所建议的那样,您可以通过将正则表达式中的 .+? 替换为与引号不匹配的内容来做到这一点,例如 [^""]+

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

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

    您可以做其他事情来进一步优化正则表达式,包括原子组和负前瞻,但这可能会尽可能快:

    @"""([^""<>]+/thumbs/[^""<>]+)"""
    

    【讨论】:

      【解决方案3】:

      如果您要解析 (X)HTML,请考虑使用适当的解析器。

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

      【讨论】:

        【解决方案4】:

        问题是.+?也消耗 "s,因此它继续匹配 src 属性之外的内容。改用它:

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

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

          • 会自动缓存一定数量的 Regex 对象,因此在字段中存储一个对象不一定会对性能产生任何影响。此外,Compiled 正则表达式可能更快,但创建它们的成本要高得多;您是否应该使用该选项取决于您如何使用正则表达式。 blogs.msdn.com/bclteam/archive/2004/11/12/256783.aspx
          猜你喜欢
          • 2011-09-01
          • 1970-01-01
          • 2020-03-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-17
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多