我读到要停止正则表达式的回溯,可以使用否定的字符类。就像我们希望匹配<Em>
中的This <Em>is the shiz <Em>
一样,我们可以使用比<[^>]+>
更快的<.+?>
,因为后者在每个字符之后回溯,但前者不会回溯到所有。
有人可以解释&lt; [^&gt;] +&gt;内部匹配?
答案 0 :(得分:3)
你必须先了解贪婪和懒惰的量词是如何工作的。
如果后面的子模式(在您的示例中为>
)匹配,则惰性量词将测试每个字符。贪心量词将采用所有可能的字符,并且只有在需要之后才会回溯以使下一个子模式(在您的示例中为>
)匹配。
但是如果不使用点(除了换行符之外的所有符号),你使用的是一个不包含字符>
的否定字符类,你肯定没有回溯的步骤。我希望能够清楚!
为了说明我的意见,建议您使用http://regex101.com的调试器尝试这三种模式:<.*>
,<.*?>
,<[^>]*>
使用此字符串:<abcd efgh="ijkl" mnop="qrst"> lapin
特别关于PCRE:PCRE lib默认使用自动内部优化进行编译。如果使用否定字符类后跟排除字符,则量词会自动转换为占有量词。此功能只能在编译时更改。 (source)。它可能与Perl相同。
答案 1 :(得分:2)
.+?>
之间匹配路径的主要区别在于,为了匹配当前字符, .+?>
必须查看以下字符,其中[^>]+
为不即可。 [^>]+
表示&#34;匹配一个或多个不是>
的字符......它只会吃掉它们而不再考虑它们。
为什么.+?>
需要向前看并导致回溯?
相比之下,在每一步中,.+?>
向前迈出一步然后退一步。为什么?
我们假设您尝试使用thing>
匹配.+?>
。在第一步,在t
前面,因为?
是懒惰的, .+?>
中的点匹配零个字符。然后引擎前进到下一个角色。在那里,尝试匹配>
,但未通过。因此引擎回溯,然后懒惰的量词从沙发上下来并允许点匹配。对h,i,n和g重复该过程:对于每个字符,惰性点首先匹配零个字符;然后引擎尝试匹配>
,失败,回溯并匹配该字母。
这在RegexBuddy调试器中清楚地显示,其中RB尝试使用thing>
匹配.+?>
将此与此屏幕截图进行比较,其中RB尝试使用thing>
[^>]+>
答案 2 :(得分:0)
有人可以解释一下&lt; [^&gt;] +&gt;内部匹配?
实际上,这是更容易理解的。它说:
Match the sequence
1) one '<'
2) at least one (as many as posible) '[^>]' (i.e.: any character except for '>')
3) one '>'
然后,在This <Em>is the shiz <Em>
搜索的匹配器将完成预期的操作。从头开始,它将(暂时)匹配第一个<
,然后转到第2部分,然后匹配Em
然后转到第3部分... ...并找到{{1} }:完成!
使用>
指令是:
<.*?>
现在,从头开始,它将(暂时)与第一个Match the sequence
1) one '<'
2) any amount (least possible) of '.' (i.e.: any character)
3) one '>'
匹配,然后转到第2部分,并且(这里是第一个区别)它首先会说,“嘿,我找到了一个空字符串(<
和<
之间的那个,它与第2步匹配,让我们进入第3步“。但是它会失败(“我发现了一个E
,我期待一个E
;然后它会回到模式序列中(但不是在输入序列中!我不会称之为回溯,只是向前看分支,好吧,让我们尝试匹配>
进行步骤2)(它匹配,继续......)它会再次失败......但是在下一次重复中它会成功。
所以这在功能上是等效的,效率稍差。
请注意,如果模式没有在那里结束,那么替代方案在功能上并不相同。例如,如果模式是:E
并且我给它输入<.*?><br>
它将匹配hi <em>hello ! <em><br>bye
,这不是您可能想要的。
答案 3 :(得分:0)
a+
会保持匹配的字符,直到达到不是a
的字符。
[a-z]+
会保持匹配字符,直到达到不是a
,z
或其中之间的字符。
[^a-z]+
保持匹配字符,直到达到 a
,z
或其中之间的某个字符。对于匹配器,否定字符类和常规字符类的工作方式完全相同;只是在正则表达式构造时,反转列表被翻转,以便不仅仅匹配指定范围内的 ,它只匹配指定范围内的 。