preg_replace 混乱

preg_replace confusion

在包含一些 html 的字符串中,我想查找并替换每个出现的 <h1-6> 标记,包括它后面的任何内容,直到另一个 <h1-6> 标记或直到html 字符串的末尾。

我的模式:<h\d.+?(?=<h\d)

使用 /gs 标志,此模式在 this online testing tool.

上运行良好

然而,在服务器端测试中,我只能使我的模式匹配第一次出现,而其余的则被忽略。

PHP Manual 状态:

Searches subject for matches to pattern and replaces them with replacement.

Another post answer 提及:

preg_replace() will perform global replacements by default

根据以上所述,如果更改为 /<h\d.+?(?=<h\d)/s,我的服务器端模式应该可以正常工作,但出于某种原因,它仍然只替换了第一次出现的内容。

完整代码:

$html = get_html_string();
$pattern = '/<h\d.+?(?=<h\d)/s';
$replace = '<div>[=11=]</div>';
$html = preg_replace($pattern, $replace, $html);
return $html;


更新:

看起来我的 html 示例与网站上的实际 html 有点不同。因此,我确保将我想要直接操作的字符串复制到在线测试器工具中。现在很明显匹配有效,但实际问题是最后一个匹配不包括在内。参见 this updated test

感谢 Nick 的回答和其他人的参与。

您有几个问题:

  1. 您需要 g(全局)标志才能获得多个匹配项
  2. 您需要添加 $(字符串结尾)作为前瞻的替代,以便它可以匹配最后一个 <hn> 标记的字符串结尾。

这应该可以满足您的要求:

<h\d.+?(?=<h\d|$)

Demo on regex101

在PHP中:

preg_match_all('/<h\d.+?(?=<h\d|$)/s', $html, $matches);
print_r($matches[0]);

输出:

Array
(
    [0] => <h1> attribute="whatever">asiponfpweg ihnasegio</h1>asd
<p>whatever</p>
<img src=""></img>
    [1] => <h3> attribute="whatever">asiponfpweg ihnasegio</h3>
<p>whatever</p>
<p>whatever</p>
    [2] => <h1><span> attribute="whatever">asiponfpweg ihnasegio</span></h3>
<p>whatever</p>
    [3] => <h3> attribute="whatever">asiponfpweg ihnasegio</h3>
)

Demo on 3v4l.org