【问题标题】:How to replace all XHTML/HTML line breaks (<br>) with new lines?如何用新行替换所有 XHTML/HTML 换行符 (<br>)?
【发布时间】:2011-01-27 00:39:07
【问题描述】:

我正在寻找最好的br2nl 函数。我想用换行符\n 替换&lt;br&gt;&lt;br /&gt; 的所有实例。很像 nl2br() 函数,但相反。

我知道 PHP 手册 cmets 中有几种解决方案,但我正在寻找 SO 社区关于可能解决方案的反馈。

【问题讨论】:

  • 您确定要用物理换行符替换 HTML/XHTML 换行符吗?因为nl2br 不会替换物理换行符,而只是添加 HTML/XHTML 换行符元素。
  • 我没有使用这个函数来否定或恢复从 nl2br 返回的字符串。在将旧数据库(来自允许 html 的 web 应用程序)中的文本导入数据库之前,我正在使用它来清理文本。我刚才说的是 nl2br 的反面,因为人们通常都知道这个功能。

标签: php regex newline


【解决方案1】:

您应该使用PHP_EOL 常量来获得独立于平台的换行符。

在我看来,尽可能使用非正则表达式函数会使代码更具可读性。

$newlineTags = array(
  '<br>',
  '<br/>',
  '<br />',
);
$html = str_replace($newlineTags, PHP_EOL, $html);

我知道此解决方案存在一些缺陷,但仍想分享我的见解。

【讨论】:

  • 而正则表达式通常需要更繁重的计算。
  • @BenBITDesign 关于您建议的编辑,请注意,绝对不是真的正则表达式通常需要更多计算。事实上,如果没有对这种特定情况进行计时,PCRE 引擎很可能比str_replace 更有效地执行此替换,尤其是在启用即时编译的情况下。
【解决方案2】:

我通常会说“不要使用正则表达式来处理 HTML”,但是在这个问题上,我可能会使用正则表达式,因为&lt;br&gt; 标签通常看起来像:

  • &lt;br&gt;
  • &lt;br/&gt;/ 之前有任意数量的空格


我想这样的事情可以解决问题:

$html = 'this <br>is<br/>some<br />text <br    />!';
$nl = preg_replace('#<br\s*/?>#i', "\n", $html);
echo $nl;

几个笔记:

  • &lt;br开头
  • 后跟任意数量的白色字符:\s*
  • 可选,//?
  • 最后是&gt;
  • 这使用不区分大小写的匹配 (#i),因为&lt;BR&gt; 在 HTML 中有效

【讨论】:

  • 这是对正则表达式的一个很好的解释。
  • 非常挑剔 =] : &lt;input type="text" value="&lt;br /&gt;"&gt; 在 html 中是允许的(不是 xhtml)。在 CDATA 部分中,&lt;br /&gt; 是“普通”文本。
  • @VolkerK : 哼,真的 :-) ;;我是用 DOM 写这个的,当我完成时,我看到你发布了与我提出的相同类型的解决方案 (除了我使用 getElementsByName,而不是 XPath),所以没有发布它 - - 不过,为了完整起见,也许我应该编辑我的答案,因为它已被接受......
  • 但是这个解决方案速度更快,内存消耗更少(如果这是一个问题)。如果您没有完全任意文档,我可能会认为这些边缘情况是可以接受的。
  • 第二个参数不应该是“\\n”吗?这是唯一适用于我的设置的东西。
【解决方案3】:

如果文档格式正确(或至少格式正确),您可以使用 DOM extension 和 xpath 来查找所有 br 元素并将其替换为 \n 文本节点。

$in = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html><head><title>...</title></head><body>abc<br />def<p>ghi<br />jkl</p></body></html>';

$doc = new DOMDOcument;
$doc->loadhtml($in);
$xpath = new DOMXPath($doc);

$toBeReplaced = array();
foreach($xpath->query('//br') as $node) {
    $toBeReplaced[] = $node;
}

$linebreak = $doc->createTextNode("\n");
foreach($toBeReplaced as $node) {
    $node->parentNode->replaceChild($linebreak->cloneNode(), $node);
}

echo $doc->savehtml();

打印

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head><title>...</title></head>
<body>abc
def<p>ghi
jkl</p>
</body>
</html>

编辑:只有一次迭代的较短版本

$in = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html><head><title>...</title></head><body>abc<br />def<p>ghi<br />jkl</p></body></html>';

$doc = new DOMDOcument;
$doc->loadhtml($in);
$xpath = new DOMXPath($doc);

$linebreak = $doc->createTextNode("\n");
foreach($xpath->query('//br') as $node) {
  $node->parentNode->removeChild($node);
}

echo $doc->savehtml();

【讨论】:

  • 你不需要做两轮。您可以将节点替换为第一个foreach
  • 好像是这样 ;-) 出于某种(未知)原因,我记得它破坏了 xpath 迭代器。
  • 短版不添加$linebreak 节点。无论如何,这正是我所需要的,谢谢。
【解决方案4】:

来自nl2brcmets:

<?php
function br2nl($string){
  $return=eregi_replace('<br[[:space:]]*/?'.
    '[[:space:]]*>',chr(13).chr(10),$string);
  return $return;
}
?> 

【讨论】:

  • posix 正则表达式模块已被弃用。来自 ereg_replace 手册页:“此功能自 PHP 5.3.0 起已弃用,自 PHP 6.0.0 起已删除。强烈建议不要依赖此功能。”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-09
  • 1970-01-01
  • 2010-10-21
  • 1970-01-01
  • 2011-11-14
  • 1970-01-01
相关资源
最近更新 更多