【问题标题】:preg_replace regex to remove stray end tagpreg_replace 正则表达式以删除杂散的结束标记
【发布时间】:2026-01-27 01:00:02
【问题描述】:

我有一个字符串,其中包含不同类型的 html 标记和内容,包括一些 <img> 元素。我正在尝试将这些 <img> 元素包装在 <figure> 标记中。到目前为止,使用这样的 preg_replace 非常好:

preg_replace( '/(<img.*?>)/s','<figure>$1</figure>',$content); 

但是,如果&lt;img&gt;标签有一个相邻的&lt;figcaption&gt;标签,结果就相当难看,并且会为图形元素产生一个杂散的结束标签:

<figure id="attachment_9615">
<img class="size-full" src="http://www.example.com/pic.png" alt="name" width="1699" height="354" />
<figcaption class="caption-text"></figure>Caption title here</figcaption>
</figure> 

我尝试了一大堆 preg_replace 正则表达式变体来将 img-tag 和 figcaption-tag 包装在图中,但似乎无法使其工作。

我最近的尝试:

preg_replace( '/(<img.*?>)(<figcaption .*>*.<\/figcaption>)?/s',
'<figure">$1$2</figure>',
$content); 

【问题讨论】:

  • 我可以建议不要使用正则表达式来完成这项任务吗?你考虑过 DOM 解析器吗?
  • @RocketHazmat 好吧,当然。如果您知道在 Wordpress 中执行此操作的另一种方法,目的是清理 FB Instant Articles 的 RSS 提要输出。我可能可以删除一些 Wordpress 内容过滤器,然后重做所有过滤器,但是正则表达式不是...更简单吗?
  • @AbraCadaver 谢谢,我会做一些阅读!

标签: php regex preg-replace


【解决方案1】:

正如其他人指出的那样,最好使用解析器,即DOMDocument。以下代码在每个 img 周围包装了一个 &lt;figure&gt; 标记,其中下一个兄弟是 &lt;figcaption&gt;

<?php

$html = <<<EOF
<html>
    <img class="size-full" src="http://www.example.com/pic.png" alt="name" width="1699" height="354" />
    <figcaption class="caption-text">Caption title here</figcaption>

    <img class="size-full" src="http://www.example.com/pic.png" alt="name" width="1699" height="354" />

    <img class="size-full" src="http://www.example.com/pic.png" alt="name" width="1699" height="354" />
    <figcaption class="caption-text">Caption title here</figcaption>
</html>
EOF;

$dom = new DOMdocument();
$dom->loadHTML($html);
$xpath = new DOMXPath($dom);

# get all images
$imgs = $xpath->query("//img");

foreach ($imgs as $img) {
    if ($img->nextSibling->tagName == 'figcaption') {

        # create a new figure tag and append the cloned elements
        $figure = $dom->createElement('figure');
        $figure->appendChild($img->cloneNode(true));
        $figure->appendChild($img->nextSibling->cloneNode(true));

        # insert the newly generated elements right before $img
        $img->parentNode->insertBefore($figure, $img);

        # and remove both the figcaption and the image from the DOM
        $img->nextSibling->parentNode->removeChild($img->nextSibling);
        $img->parentNode->removeChild($img);

    }
}
$dom->formatOutput=true;
echo $dom->saveHTML();

a demo on ideone.com

要在您的所有图像周围添加&lt;figure&gt; 标签,您可能需要添加else 分支:

} else {
    $figure = $dom->createElement('figure');
    $figure->appendChild($img->cloneNode(true));
    $img->parentNode->insertBefore($figure, $img);

    $img->parentNode->removeChild($img);
}

【讨论】: