正则表达式:在PHP中将非块元素转换为<p> </p>

时间:2011-09-01 22:39:25

标签: php html regex

有人问similar question,但接受的答案不符合我的要求。

输入:

<strong>bold <br /><br /> text</strong><br /><br /><br />
<a href="#">link</a><br /><br />
<pre>some code</pre>
I'm a single br, <br /> leave me alone.

预期输出:

<p><strong>bold <br /> text</strong><br /></p>
<p><a href="#">link</a><br /></p>
<pre>some code</pre>
<p>I'm a single br, <br /> leave me alone.</p>

我上面提到的接受的答案会将多个br转换为p,最后将所有输入换成另一个p。但在我的情况下,你不能将pre包装在p标签内。有人可以帮忙吗?

更新

此编辑之前的预期输出有点令人困惑。重点是:

  1. 将多个br转换为单个br(使用preg_replace('/(<br />)+/', '<br />', $str);实现)

  2. 检查内联元素和未解包的文本(在这种情况下没有父元素,输入来自$ _POST)并使用&lt; p&gt;换行,只保留块级元素。

2 个答案:

答案 0 :(得分:3)

使用正则表达式。为什么?请参阅:RegEx match open tags except XHTML self-contained tags

使用适当的DOM操纵器。请参阅:http://php.net/manual/en/book.dom.php

编辑: 我真的不喜欢提供食谱 - 食谱,所以这里有一个解决方案,可以将<br />的{​​{1}}更改为包裹在<p></p>中的文字:

script.php:
<?php

function isBlockElement($nodeName) {
  $blockElementsArray = array("pre", "div"); // edit to suit your needs
  return in_array($nodeName, $blockElementsArray);
}

function hasBlockParent(&$node) {
  if (!($node instanceof DOMNode)) {
    // return whatever you wish to return on error
    // or throw an exception
  }
  if (is_null($node->parentNode))
    return false;

  if (isBlockElement($node->parentNode))
    return true;

  return hasBlockParent($node->parentNode);
}

$myDom = new DOMDocument;
$myDom->loadHTMLFile("in-file");
$myDom->normalizeDocument();


$elems =& $myDom->getElementsByTagName("*");
for ($i = 0; $i < $elems->length; $i++) {
  $element =& $elems->item($i);
  if (($element->nextSibling->nodeName == "br" && $element->nextSibling->nextSibling->nodeName == "br") && !hasBlockParent($element)) {
    $parent =& $element->parentNode;
    $parent->removeChild($element->nextSibling->nextSibling);
    $parent->removeChild($element->nextSibling);

    // check if there are further nodes on the same level
    $nSibling;
    if (!is_null($element->nextSibling))
      $nSibling = $element->nextSibling;
    else
      $nSibling = NULL;

    // delete the old node
    $saved = $parent->removeChild($element);
    $newNode = $myDom->createElement("p");
    $newNode->appendChild($saved);
    if ($nSibling == NULL)
      $parent->appendChild($newNode);
    else 
      $parent->insertBefore($newNode, $nSibling);
  }
}

$myDom->saveHTMLFile("out-file");

?>

这不是一个完整的解决方案,但它是一个起点。这是我在午休期间写的最好的,请记住我上次用PHP编写的时间大约是2年前(从那时起主要做的是C ++)。我不是把它写成一个完整的解决方案,而是给你一个......好吧,起点:)

无论如何,输入文件:

[dare2be@schroedinger dom-php]$ cat in-file
<strong>bold <br /><br /> text</strong><br /><br /><br />
<a href="#">link</a><br /><br />
<pre>some code</pre>
I'm a single br, <br /> leave me alone.

输出文件:

[dare2be@schroedinger dom-php]$ cat out-file 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><p><strong>bold <br><br> text</strong></p><br><p><a href="#">link</a></p><pre>some code</pre>
I'm a single br, <br> leave me alone.</body></html>

整个DOCTYPE mumbo jumbo是副作用。代码不会执行您所说的其他内容,例如将<bold><br><br></bold>更改为<bold><br></bold>。此外,这整个脚本是快速草稿,但你会明白这一点。

答案 1 :(得分:2)

好吧,我得到了答案,我相信这会很好用。

来自WordPress ...... wpautop function

我用输入(来自我的问题)对它进行了测试,输出几乎与我预期的相同,我只需要稍微修改它以满足我的需要。

感谢dare2be,但我对PHP中的DOM操纵器不是很熟悉。