Замените новые строки тегами BR, но только внутри тегов PRE.

В наличии PHP5, какое хорошее preg_replace выражение для выполнения этого преобразования:

заменить новые строки на <br />, но только в пределах <pre> блоков

(Не стесняйтесь делать упрощающие предположения и игнорировать угловые случаи. Например, мы можем предположить, что теги будут одной строкой, а не патологическими вещами, такими как )

Введите текст:

<div><pre class='some class'>1
2
3
</pre>
<pre>line 1
line 2
line 3
</pre>
</div>

Выход:

<div><pre>1<br />2<br />3<br /></pre>
<pre>line 1<br />line 2<br />line 3<br /></pre>
</div>

(Мотивирующий контекст: попытка закрыть ошибку 20760 в расширении wikimedia SyntaxHighlight_GeSHI и обнаружение того, что мои навыки PHP (в основном я занимаюсь python) не на высоте).

Я открыт для других решений, кроме regexen, но предпочтительнее небольшой (например, создание механизма синтаксического анализа html является излишним).


person Gregg Lind    schedule 04.10.2009    source источник


Ответы (2)


Что-то вроде этого?

<?php

$content = "<div><pre class='some class'>1
2
3
</pre>
<pre>line 1
line 2
line 3
</pre>
</div>
";

function getInnerHTML($Node)
{
     $Body = $Node->ownerDocument->documentElement->firstChild->firstChild;
     $Document = new DOMDocument();    
     $Document->appendChild($Document->importNode($Body,true));
     return $Document->saveHTML();
}

$dom = new DOMDocument();
$dom->loadHTML( $content );
$preElements = $dom->getElementsByTagName('pre');

if ( count( $preElements ) ) {
    foreach ( $preElements as $pre ) {
    $value = preg_replace( '/\n|\r\n/', '<br/>', $pre->nodeValue  );
    $pre->nodeValue = $value;
    }

    echo html_entity_decode( getInnerHTML( $dom->documentElement ) );
}
person meder omuraliev    schedule 04.10.2009
comment
обновленный ответ с html_entity_decode , удалите его, если он вам не нужен. - person meder omuraliev; 04.10.2009
comment
Я только что набросал быстрое регулярное выражение для новых строк, если вы увидите какие-либо проблемы, дайте мне знать, для вас, мастеров регулярных выражений perl :) - person meder omuraliev; 04.10.2009
comment
Это не подходит для моих целей, поскольку html_entity_decode добавляет новые строки между элементами. Не вините меня, вините класс Parser викимедиа :) - person Gregg Lind; 05.10.2009
comment
Исправление: saveHtml добавляет новые строки. Мне нравится этот подход, хотя, как правило, он просто не работает для моего приложения. - person Gregg Lind; 05.10.2009

Основываясь на том, что сказал SilentGhost (которое здесь почему-то не отображается):

<?php
$str = "<div><pre class='some class' >1
2
3
< / pre>
<pre>line 1
line 2
line 3
</pre>
</div>";

$out = "<div><pre class='some class' >1<br />2<br />3<br />< / pre>
<pre>line 1<br />line 2<br />line 3<br /></pre>
</div>";

function protect_newlines($str) {
    // \n -> <br />, but only if it's in a pre block
    // protects newlines from Parser::doBlockLevels()
    /* split on <pre ... /pre>, basically.  probably good enough */
    $str = " ".$str;  // guarantee split will be in even positions
    //$parts = preg_split('/(<pre .*  pre>)/Umsxu',$str,-1,PREG_SPLIT_DELIM_CAPTURE);
    $parts = preg_split("/(< \s* pre .* \/ \s* pre \s* >)/Umsxu",$str,-1,PREG_SPLIT_DELIM_CAPTURE);
    foreach ($parts as $idx=>$part) {
        if ($idx % 2) {
            $parts[$idx] = preg_replace("/\n/", "<br />", $part);
        }
    }
    $str = implode('',$parts);
    /* chop off the first space, that we had added */
    return substr($str,1);
}

assert(protect_newlines($str) === $out);
?>
person Gregg Lind    schedule 05.10.2009