代码之家  ›  专栏  ›  技术社区  ›  Daniel Vandersluis

使用非贪婪的限定符还是向前看更好?

  •  6
  • Daniel Vandersluis  · 技术社区  · 14 年前

    我可能有一大块文本要搜索 [[...]] ... 可以是任何东西,包括其他括号(尽管它们不能嵌套;一审 ]] 之后 [[ 比赛结束)。

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

    4 回复  |  直到 13 年前
        1
  •  6
  •   Tomalak    14 年前

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

    以这个字符串为例 "[[a]b]]"

    非贪婪量词

           \[\[.+?\]\]
    Atom # 1 2 3  4 5
    
    1. 原子#1 \[
    2. 原子2 比赛
    3. .+? "a"
    4. \] 比赛
    5. 原子5 失败,返回到#3,但保持字符串位置
    6. 原子#3 .+? "]"
    7. \]
    8. 原子#3 "b"
    9. \] 比赛
    10. 原子5 \] 比赛

    展望未来:

           \[\[(?:(?!\]\]).)+\]\]
    Atom # 1 2 3  4       5  6 7
    
    1. 原子#1 比赛
    2. \[ 比赛
    3. (?!\]\]) 立即在处成功(即不匹配) “a” ,继续
    4. . “a”
    5. (?!\]\]) "]"
    6. (?!\]\]) “b” ,继续
    7. 原子5 . "]" ,在#3重复
    8. (?!\]\]) 立即在处成功(即不匹配) ,继续
    9. 原子5 . “b”
    10. 达到部分匹配
    11. 原子4 达到完全匹配 ,因此:#4失败,退出#3
    12. 原子#6 比赛
    13. \]
    14. 成功

    所以看起来非贪婪量词要做的工作更少。

    免责声明:这是一个人工示例,实际性能可能会有所不同,具体取决于regex引擎的输入、实际表达式和实现。我只有98%的把握,我在这里概述的是实际发生的事情,所以我愿意改正。另外,和所有的性能技巧一样,不要把这当作表面价值,如果你想确定的话,做你自己的基准比较。

        2
  •  3
  •   Markus Jarderot    14 年前

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

    它既不使用非贪婪量词,也不使用look aheads。它允许一个 ] ] . 如果有两个

    这种模式最好与FSA编译regex引擎一起使用。在回溯引擎上,它可能会比不贪婪的变体慢。

        3
  •  1
  •   Alan Moore Chris Ballance    14 年前

    你用哪种正则表达式?如果它支持所有格量词,有一个更好的选择:

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

    [^\]]++ 狼吞虎咽除了 ] 而且不需要保存状态信息,这样就可以进行回溯。如果它真的看到 ] ,它执行一个向前看的操作,以查看是否还有另一个。用另一个所有格量词包装整个事物意味着它只在看到一个事物时进行前瞻 ] ,它只回溯一次:当它找到结束时 ]] .

    Java、JGSoft、PCRE(PHP)、Oniguruma(Ruby 1.9)和perl5.12风格支持所有格量词。所有这些口味也都支持原子团,可以用来达到同样的效果:

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

    NET风格支持原子组,但不支持所有格量词。

        4
  •  0
  •   Brent Arias    14 年前

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