【问题标题】:Replace newlines with BR tags, but only inside PRE tags用 BR 标签替换换行符,但仅限于 PRE 标签内
【发布时间】:2010-12-03 18:40:28
【问题描述】:

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

(激励上下文:尝试关闭 wikimedia SyntaxHighlight_GeSHI 扩展中的错误 20760,并发现我的 PHP 技能(我主要使用 python)不合格)。

除了正则表达式之外,我对其他解决方案持开放态度,但首选较小的解决方案(例如,构建 html 解析机制是多余的)。

【问题讨论】:

    标签: php regex html-parsing


    【解决方案1】:

    这样的?

    <?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 ) );
    }
    

    【讨论】:

    • html_entity_decode 更新了答案,如果你不需要它,请将其删除。
    • 我刚刚为换行提供了一个快速的正则表达式,如果您发现任何问题,请告诉我,为您提供 perl 正则表达式向导 :)
    • 这对我来说失败了,因为 html_entity_decode 在元素之间添加了换行符。不要怪我,怪维基媒体的 Parser 类:)
    • 更正:saveHtml 添加换行符。我确实喜欢这种方法,但一般来说,它不适用于我的应用程序。
    【解决方案2】:

    根据 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);
    ?>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-07-07
      • 2020-12-09
      • 1970-01-01
      • 2011-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多