考虑这个例子:
<pre class="scooby" name="not-code">
content
</pre>
...other HTML...
<pre class="ruby" name="code">
content
</pre>
使用此正则表达式 [*]:
<pre class="(.+)" name="code">
...第一部分 - <pre class="
- 开始匹配第一个标签,然后(.+)
消耗整个文档的其余部分。但是正则表达式的其余部分 - " name="code">
- 不能在那里匹配,所以它会后退,直到找到它可以的位置 - 在第二个标签中。结果:该组最终捕获了从scooby
到的所有内容ruby
。
即使您使用 non-greedy(.+?)
而不是 greedy 也是如此(.+)
。人们经常说非贪婪量词导致正则表达式返回最短的匹配,但事实并非如此。就像一个贪婪的正则表达式,它一有机会就开始匹配;它也会尽快停止匹配。像这种非贪婪量词没有用的情况并不少见。
另一件要考虑的事情是当没有可能的匹配时——例如,如果有<pre>
第一个属性的标签class="~whatever~"
,但没有一个name="code"
属性的标签。每一次,贪婪(.+)
者都会吞噬整个文件,然后退缩,直到到达起点,然后放弃。非贪婪(.+?)
不会回溯,但它会扫描整个页面,并且会慢得多(它有效地对" name="code">
每个位置进行前瞻)。
使用这个正则表达式:
<pre class="([^"]+)" name="code">
...它永远不必扫描超出标签的末尾来确定它是否匹配。
始终考虑如果无法匹配会发生什么。这可能是正则表达式作者最常见的监督,也是导致性能问题最多的一种。
[*] 出于说明目的,我假设比赛是在 DOTALL 模式(又名单行模式)下进行的。