你能解释一下这是如何工作的吗?这是一个例子:
<!-- The quick brown fox
jumps over the lazy dog -->
<!--[if IE 7]>
<link rel="stylesheet" type="text/css" href="/supersheet.css" />
<![endif]-->
<!-- Pack my box with five dozen liquor jugs -->
首先,我尝试使用下面的正则表达式来匹配条件注释中的内容:
/<!--.*?stylesheet.*?-->/s
它失败了,因为正则表达式匹配了第一个 <!--
之前的所有内容最后一个 -->
.然后我尝试使用另一种带有先行断言的模式:
/<!--(?=.*?stylesheet).*?-->/s
它的工作原理完全符合我的需要。但是,以下正则表达式也适用:
/<!--(?=.*stylesheet).*?-->/s
最后一个正则表达式在先行断言中没有不情愿的量词。现在我很困惑。任何人都可以向我解释它是如何工作的吗?也许这个例子有更好的解决方案?
更新:
我尝试在另一个文档中使用带有先行断言的正则表达式,但无法处理注释之间的内容。所以,这个 /<!--(?=.*?stylesheet).*?-->/s
(以及这个 /<!--(?=.*stylesheet).*?-->/s
)不正确。不要使用它并尝试其他建议。
更新:
解决方案已被 Jonny 5 找到(参见答案)。他提出了三个选项:
- 使用否定连字符来限制匹配。此选项仅在标签之间没有连字符时才有效。如果样式表的 URL 为
/style-sheet.css
, 它不会起作用。 - 使用转义序列:
\K
.它就像一个魅力。缺点如下:- 它非常慢(在我的例子中,它比其他解决方案慢 8-10 倍)
- 仅在 PHP 5.2.4 之后可用
- 使用前瞻来缩小匹配范围。这是我试图实现的目标,但我使用环视断言的经验不足以执行该任务。
我认为以下是我的示例的一个很好的解决方案:
/(?s)<!--(?:(?!<!).)+?stylesheet.+?-->/
相同但带有 s
末尾修饰符:
/<!--(?:(?!<!).)+?stylesheet.+?-->/s
正如我所说,这是一个很好的解决方案,但我设法改进了模式并找到了另一个在我的情况下运行速度更快的模式。
所以,最终的解决方案如下:
/<!--(?:(?!-->).)+?stylesheet.+?-->/s
感谢所有参与者有趣的回答。
最佳答案
只匹配<!--
部分... stylesheet
... -->
有很多方法:
1.) 使用 negated连字符 [^-]
限制比赛并停留在<!--
之间和 stylesheet
(?s)<!--[^-]+stylesheet.+?-->
[^-]
只允许不是连字符的字符。参见 test at regex101 .
2.) 要获得“最后”或最接近的匹配而不需要太多正则表达式的努力,也可以输入 greedy dot之前要ᗧ吃完。如果不匹配全局/仅匹配一个项目,则有意义。使用 \K to reset贪婪之后:
(?s)^.*\K<!--.+?stylesheet.+?-->
参见 test at regex101 .也可以使用 capture group and grab $1: (?s)^.*(<!--.+?stylesheet.+?-->)
3.) 使用 lookahead缩小范围通常成本更高:
(?s)<!--(?:(?!<!).)+?stylesheet.+?-->
参见 test at regex101 . (?!<!).
向前看 <!--
之间的每个字符和 stylesheet
如果不开始另一个 <!
...留在一个元素内。类似于否定连字符解决方案。
而不是 .*
我用了.+
对于一个或多个 - 取决于要匹配的内容。这里+
更合身。
使用什么解决方案取决于具体要求。对于这种情况,我会使用第一个。
关于php - 正则表达式练习 : reluctant quantifier with a lookahead assertion,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32031058/