【问题标题】:PCRE (php) regex, subpattern with + matches and with * doesn't?PCRE (php) 正则表达式,带有 + 匹配和带有 * 的子模式不匹配?
【发布时间】:2011-01-31 12:33:19
【问题描述】:

我想在 html 文档中匹配并捕获 所有现有(如果有) <style...</style> 块和 一个 <body..</body> 块的内部。 我认为这很简单,但我遇到了一些奇怪的事情。 这是我对整个正则表达式的猜测:

/(<style[\s\S]+<\/style>)*[\s\S]*<body.*>([\s\S]+)<\/body>/i

结果一无所获。所以我把它拆开,这些部分工作:

/(<body.*>([\s\S]+)<\/body>)/i
/(<style[\s\S]+<\/style>)/i

最奇怪的第一行也有效,而第二行结果为空!

/(<style[\s\S]+<\/style>)+/i
/(<style[\s\S]+<\/style>)*/i

所以,我猜错误是子模式后 * 和 + 之间的区别。为什么?我该如何解决这个问题?

谢谢!!

【问题讨论】:

    标签: php regex pcre


    【解决方案1】:

    你有四个问题:

    第一和第二,您正在使用正则表达式来解析 HTML。

    第三,你匹配的太多了:你至少需要让一些量词变得懒惰,即。 e.使用.*?[\s\S]*? 等,否则您的正则表达式将匹配所有内容直到行或文件的末尾,然后只回溯尽可能多的内容以找到最后一个可能的匹配标签。

    第四,通过在重复组中设置重复组,您已经为灾难性的回溯做好了准备,这两种方法都有无数种方法来匹配相同的文本。

    据我了解您的问题,您希望匹配从第一个 &lt;style&gt; 标记到最后一个 &lt;/body&gt; 的所有内容,并捕获所有 &lt;style&gt; 标记的内容和 &lt;body&gt; 标记的内容。正确的?那就试试吧

    /(<style[\s\S]+<\/style>)[\s\S]*?<body.*?>([\s\S]+)<\/body>/i
    

    要分别捕获每个&lt;style&gt; 块,您可以尝试最多四个可能的&lt;style&gt; 块:

    /(<style[\s\S]+?<\/style>)?\s*(<style[\s\S]+?<\/style>)?\s*(<style[\s\S]+?<\/style>)?\s*(<style[\s\S]+?<\/style>)?\s*<body.*?>([\s\S]+)<\/body>/i
    

    如果&lt;style&gt; 块都相邻并且仅由空格分隔。您能明白为什么为此使用正则表达式不是一个好主意吗?

    【讨论】:

    • 虽然您的正则表达式可以工作,但它并不能独立捕获样式块。例如,如果 2 个样式块直接接踵而至,那么您的解决方案是可以的,但是如果您在 thh 样式块之间有一些字符串,它会将它包含在结果中,这是我不想要的。所以,只有样式本身会阻塞。
    • 那写得模棱两可。让我举个例子:yyy。您的解决方案给了我不想要的 yyy。
    • 您无法独立捕获&lt;style&gt; 块。至少不是在 JavaScript 中; .NET 具有允许这样做的功能,但大多数正则表达式引擎不允许(除非您事先知道最多可以重复多少次)。我的解决方案从第一个到最后一个 &lt;style&gt; 块匹配,这是你可以用 JS 正则表达式做的最好的。
    • 如果我说,可以有最大。 4 个样式块?
    • 也许“独立”不是正确的术语。它可能匹配 1 个捕获,但没有我的示例中的 yyy。 (我的知识并没有深入到您上一个答案中是否包含该内容。抱歉,如果我错过了。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-25
    • 1970-01-01
    • 2016-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多