我正在看Regex的教程。
它是关于如何从这段html中获取class属性
<pre class="ruby" name="code">
使用的正则表达式是
<pre class="([^"]+)" name="code">
他们建议使用上面的那个而不是
<pre class="(.+)" name="code">
“因为它超出了报价。”
我不明白他们的意思。无论如何它只是工作但是为什么推荐第一个正则表达式。我错过了什么吗?请赐教。
提前致谢。
答案 0 :(得分:4)
.+
贪婪地匹配。例如,在
<pre class="ruby" size="medium" name="code">
它会匹配ruby" size="medium
。更糟糕的是,如果在同一行上有两个标记,它将在标记边界上匹配:
<pre class="ruby" name="code">foo</pre> <pre class="python" name="code">bar</pre>
会产生ruby" name="code">foo</pre> <pre class="python
!
因此,只要您确切了解HTML的外观,.+
就可以正常工作,但只要它意外地发生变化(因为HTML不会这样做),您的正则表达式就不会失败(如第二个会)但它会匹配错误的东西。
因此,第二个正则表达式更安全(因为它更准确地说明允许匹配的内容)。您通常应该尽量避免使用简单的.+
或.*
“匹配任何内容”,而应考虑您想要匹配的内容。
也就是说,出于完全相同的原因,你不应该尝试将HTML和其他标记语言与正则表达式匹配,因为有更好的工具。
答案 1 :(得分:2)
正则表达式匹配通常会尝试匹配最长的正则表达式。因此&#34;([^&#34;] +)&#34;只匹配它遇到的第一个引用。另一方面,&#34;(。+)&#34;将从第一个引用匹配到字符串中的 last 引用。
例如,如果我们将它们应用于您的问题,则第一个匹配"ruby"
,因为它是您问题中的第一个引用字符串。第二个匹配从"ruby
到beyond the quote"
一直匹配,因为它是问题中的最后一个引号(并且还包括其他几个引用的字符串。
答案 2 :(得分:2)
考虑这个例子:
<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
的所有内容。
即使您使用非贪婪的(.+?)
而非贪婪的(.+)
,也是如此。人们常说非贪婪量词导致正则表达式返回最短的匹配,但事实并非如此。就像贪婪的正则表达式一样,在第一次机会时开始匹配;它只是停止匹配。像这样的情况,非贪婪量词没有好处,并不罕见。
另一件需要考虑的事情是,当不可能匹配时 - 例如,如果<pre>
个标签带有第一个属性class="~whatever~"
,但没有带有name="code"
属性的标签。在每一个,贪婪的(.+)
将吞噬整个文件,然后退回,直到它到达起点然后放弃。非贪婪的(.+?)
不会回溯,但它会扫描整个页面,它会更慢地执行它(它有效地在每个位置对" name="code">
进行预测)。
这个正则表达式:
<pre class="([^"]+)" name="code">
...它永远不必扫描超出标签的末尾以确定它是否匹配。
始终考虑如果不可能匹配会发生什么。这可能是最常见的监督正则表达式作者,也是导致性能问题最多的那个。
[*]我假设比赛正在DOTALL模式(a.k.a。单线模式)进行,仅供参考。
答案 3 :(得分:1)
取消课程通常会更加具体地说明您想要匹配的内容,并有助于防范Catastrophic Backtracking等情况。
杰夫阿特伍德不久前写了一篇有趣的blog post,他举了一个看似无辜的正则表达式的例子:(x+x+)+y
可以(几乎)永远地完成处理。即使主题很小,也是如此:xxxxxxxxxxxxxxxxxxxx
。
给它一个阅读,它真的很有趣。