Замена конечных тегов div с помощью функции preg_replace_callback - PullRequest
1 голос
/ 07 января 2012

Я пытаюсь разработать скрипт PHP, который заменяет все div в строке HTML на абзацы, кроме тех, которые имеют атрибуты (например, <div id="1">). Первое, что в данный момент делает мой скрипт, это использует простую str_replace () для замены всех вхождений <div> на <p>, и это оставляет любые теги div с атрибутами и конечными тегами div (</div>). Однако заменить теги </div> на теги </p> немного сложнее.

Пока что я разработал функцию preg_replace_callback, которая предназначена для преобразования некоторых тегов </div> в теги </p> для соответствия открывающим тегам <p>, но игнорирует другие теги </div>, когда они заканчиваются на <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;
?>

Сценарий в основном помещает все оставшиеся теги <div> и </div> в массив, а затем перебирает его. Затем переменная счетчика увеличивается, когда встречается с тегом <div>, или уменьшается, когда встречается с </div> в массиве. Когда счетчик меньше 0, возвращается тег </p>, в противном случае возвращается </div>. Вывод скрипта должен быть;

<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>

Я потратил часы на внесение в сценарий столько правок, сколько мог придумать, и продолжаю получать один и тот же вывод. Может кто-нибудь объяснить мне, где я иду не так или предложить альтернативное решение?

Буду признателен за любую помощь.

Ответы [ 2 ]

1 голос
/ 08 января 2012

Я использовал другой подход с несколькими регулярными выражениями:

$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>

Если вам не нужен фрагмент, я, по крайней мере, узнал кое-что о регулярных выражениях: P

1 голос
/ 08 января 2012

Рядом с тем, что прокомментировал Марио, сравнимо с phpquery или querypath, вы можете использовать класс PHP DOMDocument для поиска соответствующих элементов <div> и замены их элементами <p>.

краеугольными камнями являются 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>
...