RegExp练习:带有前瞻性断言的不情愿量词



你能解释一下这是怎么回事吗?下面是一个例子:

<!-- 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找到(见答案)。他提出了三个选择:

  1. 使用负连字符限制匹配。此选项仅在标记之间没有连字符时有效。如果样式表有一个URL /style-sheet.css,它将无法工作。
  2. 转义序列的使用:K。这招很管用。缺点如下:
    • 它非常慢(在我的情况下,它比其他解决方案慢8-10倍)
    • 仅在PHP 5.2.4之后可用
  3. 使用向前看来缩小匹配范围。这是我试图实现的目标,但是我使用lookaround断言的经验不足以执行该任务。

我认为下面是我的例子的一个很好的解决方案:

/(?s)<!--(?:(?!<!).)+?stylesheet.+?-->/

相同,但末尾加了s修饰符:

/<!--(?:(?!<!).)+?stylesheet.+?-->/s

正如我所说,这是一个很好的解决方案,但我设法改进了模式,并找到了另一个在我的情况下工作得更快的模式。

所以,最终的解决方案如下:

/<!--(?:(?!-->).)+?stylesheet.+?-->/s

感谢各位嘉宾的精彩回答。

只匹配部分<!--stylesheet……-->有很多方法:

1)。使用否定的连字符[^-]来限制匹配,并保持在<!--stylesheet之间

(?s)<!--[^-]+stylesheet.+?-->

[^-]只允许非连字符。参见regex101中的测试。


2)。为了获得"最后"或最接近的匹配而不需要太多正则表达式的努力,也可以在ᗧ吃掉之前放一个贪心点。如果不匹配全局/只有一个项目要匹配,则有意义。

(?s)^.*K<!--.+?stylesheet.+?-->

参见regex101中的测试。也可以使用捕获组抓取$1:(?s)^.*(<!--.+?stylesheet.+?-->)


3)。使用前瞻来缩小范围通常代价更高:

(?s)<!--(?:(?!<!).)+?stylesheet.+?-->

参见regex101中的测试。如果不开始另一个<!, (?!<!).将在<!--stylesheet之间查看每个字符…呆在一个元素里。类似于负连字符解决方案。


我用.+代替.*来表示一个或多个,这取决于要匹配的内容。这里+更合适。
使用哪种解决方案取决于具体的要求。在这种情况下,我将使用第一个

字符串stylesheet在您的测试文档中只被提及一次,因此您尝试的两个正则表达式将以不同的方式匹配相同的东西。

<!--(?=.*?stylesheet).*?-->/s

这个做了以下的事情:

  • Capture <!-- .
  • 向前看,捕获字符直到并包括stylesheet
  • 捕获-->以内的字符
<!--(?=.*stylesheet).*?-->/s

这个做了以下的事情:

  • Capture <!-- .
  • 向前看,捕捉任何字符,直到不再可能。回溯,不断尝试匹配stylesheet
  • 捕获-->以内的字符

基本上,一个需要明显地回溯,而另一个不需要。

如果你的主题是…

<>之前& lt; !——敏捷的棕色狐狸跳过懒狗——>& lt; !—[如果IE 7]>样式表& lt;链接rel = " <我> " type = " text/css " href = "/supersheet.css "/> & lt; !(endif)——>& lt; !——用五打样式表包装我的盒子s ->之前

会得到两个不同的结果。前者将找到第一个stylesheet,而后者将找到第二个(也是最后一个),因为它从字符串的末尾开始搜索。

相关内容

  • 没有找到相关文章

最新更新