使用非贪婪的限定词或前瞻是否更好?

时间:2010-06-04 16:21:10

标签: regex performance regex-greedy

我有一个可能很大的文本块来搜索[[...]]的实例,其中...可以是任何东西,包括其他括号(尽管它们不能嵌套; {{1}的第一个实例} ]]结束匹配后。}

我可以想到两种匹配此文本的方法:

  • 使用非贪婪的限定符:[[
  • 使用前瞻:/\[\[.+?\]\]/

从性能的角度来看,一种选择本质上比另一种更好(我说第一种选择可能更具可读性)?我记得读过最好不要使用非贪婪的限定符,但我现在找不到它的来源。

4 个答案:

答案 0 :(得分:6)

在这种情况下,最好使用非贪婪的量词。

以示例字符串"[[a]b]]"

为例

非贪婪量词

       \[\[.+?\]\]
Atom # 1 2 3  4 5
  1. Atom#1 \[匹配
  2. Atom#2 \[匹配
  3. Atom#3 .+?"a"
  4. 相匹配
  5. Atom#4 \]匹配
  6. Atom#5 \]失败,回到#3但保持字符串位置
  7. Atom#3 .+?"]"
  8. 相匹配
  9. Atom#4 \]失败,回到#3但保持字符串位置
  10. Atom#3 .+?"b"
  11. 相匹配
  12. Atom#4 \]匹配
  13. Atom#5 \]匹配
  14. 成功
  15. 超前进:

           \[\[(?:(?!\]\]).)+\]\]
    Atom # 1 2 3  4       5  6 7
    
    1. Atom#1 \[匹配
    2. Atom#2 \[匹配
    3. 原子#4 (?!\]\])"a"处立即成功(即不匹配),继续
    4. Atom#5 ."a"匹配,在#3
    5. 处重复
    6. Atom#4 (?!\]\])"]"
    7. 达到部分匹配
    8. Atom#4 (?!\]\])"b"成功(即不匹配),继续
    9. Atom#5 ."]"匹配,在#3
    10. 处重复
    11. 原子#4 (?!\]\])"b"处立即成功(即不匹配),继续
    12. Atom#5 ."b"匹配,在#3
    13. 处重复
    14. Atom#4 (?!\]\])"]"
    15. 达到部分匹配
    16. Atom#4 (?!\]\])"]"达到完全匹配,ergo:#4失败,退出#3
    17. Atom#6 \]匹配
    18. Atom#7 \]匹配
    19. 成功
    20. 所以看起来非贪婪量词的工作量较少。

      免责声明:这是一个人为的例子,真实性能可能会有所不同,具体取决于输入,实际表达式和正则表达式引擎的实现。我只有98%确定我在这里概述的是实际发生的事情,所以我愿意接受更正。此外,与所有性能提示一样,如果您想确切了解,请不要将其视为面值,进行自己的基准比较。

答案 1 :(得分:3)

另一种变体:/\[\[((?:\]?[^]])+)]]/

它既不使用非贪婪量词也不使用前瞻。它允许在任何非]之前使用单个]。如果顺序中有两个],则内部重复将停止,并且匹配将结束。

此模式最适合与FSA编译正则表达式引擎一起使用。在反向跟踪引擎上,它可能比非贪婪的变体慢。

答案 2 :(得分:1)

你使用哪种正则表达式?如果它是支持占有量词的那个,那么有一个更好的选择:

\[\[(?:[^\]]++|\](?!\]))*+\]\]

[^\]]++吞噬除]以外的任何字符,并且不会费心保存可能使回溯成为可能的状态信息。如果它确实看到],它会执行前瞻以查看是否有另一个。将整个事物包含在另一个占有量词中意味着只有在看到]时它才会前瞻,并且它只回溯一次:当它找到结束时]]

Java,JGSoft,PCRE(PHP),Oniguruma(Ruby 1.9)和Perl 5.12版本支持占有量词。所有这些口味也支持原子团,可以用来达到同样的效果:

\[\[(?>(?:(?>[^\]]+)|\](?!\]))*)\]\]

.NET风格支持原子组但不支持占有量词。

答案 3 :(得分:0)

我认为使用非贪婪的限定符会更好。你确定你读过的文章没有说“小心贪婪匹配吗?”