我有一个可能很大的文本块来搜索[[...]]
的实例,其中...
可以是任何东西,包括其他括号(尽管它们不能嵌套; {{1}的第一个实例} ]]
结束匹配后。}
我可以想到两种匹配此文本的方法:
[[
/\[\[.+?\]\]/
从性能的角度来看,一种选择本质上比另一种更好(我说第一种选择可能更具可读性)?我记得读过最好不要使用非贪婪的限定符,但我现在找不到它的来源。
答案 0 :(得分:6)
在这种情况下,最好使用非贪婪的量词。
以示例字符串"[[a]b]]"
非贪婪量词
\[\[.+?\]\] Atom # 1 2 3 4 5
\[
匹配\[
匹配.+?
与"a"
\]
匹配\]
失败,回到#3但保持字符串位置.+?
与"]"
\]
失败,回到#3但保持字符串位置.+?
与"b"
\]
匹配\]
匹配超前进:
\[\[(?:(?!\]\]).)+\]\] Atom # 1 2 3 4 5 6 7
\[
匹配\[
匹配(?!\]\])
在"a"
处立即成功(即不匹配),继续.
与"a"
匹配,在#3 (?!\]\])
在"]"
(?!\]\])
在"b"
成功(即不匹配),继续.
与"]"
匹配,在#3 (?!\]\])
在"b"
处立即成功(即不匹配),继续.
与"b"
匹配,在#3 (?!\]\])
在"]"
(?!\]\])
在"]"
达到完全匹配,ergo:#4失败,退出#3 \]
匹配\]
匹配所以看起来非贪婪量词的工作量较少。
免责声明:这是一个人为的例子,真实性能可能会有所不同,具体取决于输入,实际表达式和正则表达式引擎的实现。我只有98%确定我在这里概述的是实际发生的事情,所以我愿意接受更正。此外,与所有性能提示一样,如果您想确切了解,请不要将其视为面值,进行自己的基准比较。
答案 1 :(得分:3)
另一种变体:/\[\[((?:\]?[^]])+)]]/
它既不使用非贪婪量词也不使用前瞻。它允许在任何非]
之前使用单个]
。如果顺序中有两个]
,则内部重复将停止,并且匹配将结束。
此模式最适合与FSA编译正则表达式引擎一起使用。在反向跟踪引擎上,它可能比非贪婪的变体慢。
答案 2 :(得分:1)
你使用哪种正则表达式?如果它是支持占有量词的那个,那么有一个更好的选择:
\[\[(?:[^\]]++|\](?!\]))*+\]\]
[^\]]++
吞噬除]
以外的任何字符,并且不会费心保存可能使回溯成为可能的状态信息。如果它确实看到]
,它会执行前瞻以查看是否有另一个。将整个事物包含在另一个占有量词中意味着只有在看到]
时它才会前瞻,并且它只回溯一次:当它找到结束时]]
。
Java,JGSoft,PCRE(PHP),Oniguruma(Ruby 1.9)和Perl 5.12版本支持占有量词。所有这些口味也支持原子团,可以用来达到同样的效果:
\[\[(?>(?:(?>[^\]]+)|\](?!\]))*)\]\]
.NET风格支持原子组但不支持占有量词。
答案 3 :(得分:0)
我认为使用非贪婪的限定符会更好。你确定你读过的文章没有说“小心贪婪匹配吗?”