【问题标题】:Replacing end div tags using preg_replace_callback function使用 preg_replace_callback 函数替换结束 div 标签
【发布时间】:2012-01-07 19:21:53
【问题描述】:

我正在尝试开发一个 PHP 脚本,它将 HTML 字符串中的所有 div 替换为具有属性的段落除外(例如 <div id="1">)。我的脚本目前做的第一件事是使用一个简单的 str_replace() 将所有出现的<div> 替换为<p>,这会留下任何带有属性和结束 div 标签 (</div>) 的 div 标签。但是,用</p> 标签替换</div> 标签有点问题。

到目前为止,我已经开发了一个 preg_replace_callback 函数,该函数旨在将一些 </div> 标签转换为 </p> 标签以匹配开始 <p> 标签,但在结束 @987654334 时忽略其他 </div> 标签@ 带有属性。以下是我正在使用的脚本;

<?php
$input = "<div>Hello world!</div><div><div id=\"1\">How <div>are you</div> today?</div></div><div>I am fine.</div>";
$input2 = str_replace("<div>", "<p>", $input);
$output = preg_replace_callback("/(<div )|(<\/div>)/", 'replacer', $input2);

function replacer($matches){
    static $count = 0;
    $counter=count($matches);
    for($i=0;$i<$counter;$i++){
        if($matches[$i]=="<div "){
            return "<div ";
            $count++;
        } elseif ($matches[$i]=="</div>"){
            $count--;
            if ($count>=0){
                return "</div>";
            } elseif ($count<0){
                return "</p>";
                $count++;
            }
        }
    }
}
echo $output;
?>

该脚本基本上将所有剩余的&lt;div&gt;&lt;/div&gt; 标签放入一个数组中,然后循环遍历它。然后,计数器变量在遇到&lt;div&gt; 标记时递增,或者在遇到数组中的&lt;/div&gt; 时递减。当计数器小于 0 时,返回 &lt;/p&gt; 标签,否则返回 &lt;/div&gt;。 脚本的输出应该是;

<p>Hello world!</p><p><div id="1">How <p>are you</p> today?</div></p><p>I am fine.</p>"

相反,我得到的输出是;

<p>Hello world!</p><p><div id="1">How <p>are you</p> today?</p></p><p>I am fine.</p>

我花了几个小时对脚本进行了我能想到的尽可能多的编辑,而且我一直得到相同的输出。谁能向我解释我哪里出错或提供替代解决方案?

任何帮助将不胜感激。

【问题讨论】:

  • SO favourite off-topic joke page。 (这在任何地方都被不必要地张贴了,但由于某种原因,它从来没有真正相关过)。阅读过去的笑话;虽然大部分还是不正确的。您可以将正则表达式用于此类目的。这有点费力,需要(?R) 递归正则表达式。可行,但不值得每次有人问时单独回答。如果您只使用像phpqueryquerypath 这样的现成解决方案(html 遍历前端),则会更简单。

标签: php preg-replace-callback


【解决方案1】:

在 mario 评论的内容旁边,类似于 phpquery 或 querypath,您可以使用 PHP DOMDocument 类来搜索有问题的 &lt;div&gt; 元素并将它们替换为 &lt;p&gt; 元素。

基础是 DOM(文档对象模型)和 XPath:

$input = "<div>Hello world!</div><div><div id=\"1\">How <div>are you</div> today?</div></div><div>I am fine.</div>";

$doc = new DOMDocument();
$doc->loadHTML("<div id='body'>{$input}</div>");
$root = $doc->getElementById('body');
$xp = new DOMXPath($doc);

$expression = './/div[not(@id)]';

while($r = $xp->query($expression, $root) and $r->length)
    foreach($r as $div)
    {
        $new = $doc->createElement('p');
        foreach($div->childNodes as $child)
            $new->appendChild($child->cloneNode(1));

        $div->parentNode->replaceChild($new, $div);
    }
    ;

$html = '';
foreach($root->childNodes as $child)
    $html .= rtrim($doc->saveHTML($child))
    ;

echo $html;

这会给你:

<p>Hello world!</p><p><div id="1">How <p>are you</p> today?</div></p><p>I am fine.</p>

【讨论】:

  • 我已经运行了您建议的代码,它非常适合我显示的代码。我唯一的问题是可能有多个 div,每个 div 都有不同的 id。此外,将无法预测有多少 div 或它们可能有什么 id。我已尝试编辑您建议的代码以满足我的需求,但没有成功。不过,非常感谢您回答我的问题。
  • @siberiantiger:可以用xpath表达式控制,更简单,我来更新答案。
  • @siberiantiger:请选择对您有帮助的答案,请参阅meta.stackexchange.com/questions/5234/… - 这就是本网站的工作方式。谢谢!
【解决方案2】:

我对多个正则表达式采取了不同的方法:

$text = "<div>Hello world!</div><div><div id=\"1\">How <div>are you</div> today?</div></div><div>I am fine.</div><div>an other <div id=\"2\">small</div>test</div><div>nested<div>divs</div>...</div>";
echo "before: " . $text . "\n";

do
{
    $count1 = 0;
    $text = preg_replace("/<div>((?![^<]*?<div).*?)<\/div>/", "<p>$1</p>", $text, -1, $count1);
    $count2 = 0;
    $text = preg_replace("/<div ([^>]+)>((?![^<]*?<div).*?)<\/div>/", "<temporarytag $1>$2</temporarytag>", $text, -1, $count);
} while ($count1 + $count2 > 0);

$text = preg_replace("/(<[\/]?)temporarytag/", "$1div", $text);

echo "after: " . $text;

这会让你:

    before: <div>Hello world!</div><div><div id="1">How <div>are you</div> today?</div></div><div>I am fine.</div><div>an other <div id="2">small</div>test</div><div>nested<div>divs</div>...</div>
    after: <p>Hello world!</p><p><div id="1">How <p>are you</p> today?</div></p><p>I am fine.</p><p>an other <div id="2">small</div>test</p><p>nested<p>divs</p>...</p>

如果你不需要sn-p,我至少已经学到了一些关于正则表达式的知识:P

【讨论】:

  • 非常感谢。我也学到了一些关于正则表达式的东西。
猜你喜欢
  • 2016-01-11
  • 1970-01-01
  • 2021-06-13
  • 2014-03-09
  • 2021-01-27
  • 2015-08-09
  • 2012-12-23
  • 2016-05-24
  • 1970-01-01
相关资源
最近更新 更多