【问题标题】:Regex to remove all empty HTML tags正则表达式删除所有空的 HTML 标记
【发布时间】:2014-01-29 20:18:11
【问题描述】:

这是我的 PHP 函数,用于从字符串输入中删除所有空 HTML 标记:

/**
 * Remove the nested HTML empty tags from the string.
 *
 * @param $string String to remove tags
 * @param null $replaceTo Replace empty string with
 * @return mixed Cleaned string
 */
function crl_remove_empty_tags($string, $replaceTo = null)
{
    // Return if string not given or empty
    if (!is_string($string) || trim($string) == '') return $string;

    // Recursive empty HTML tags
    return preg_replace(
        '/<(\w+)\b(?:\s+[\w\-.:]+(?:\s*=\s*(?:"[^"]*"|"[^"]*"|[\w\-.:]+))?)*\s*/?>\s*</\1\s*>/gixsm',
        !is_string($replaceTo) ? '' : $replaceTo,
        $string
    );
}

我的正则表达式:/&lt;(\w+)\b(?:\s+[\w\-.:]+(?:\s*=\s*(?:"[^"]*"|"[^"]*"|[\w\-.:]+))?)*\s*/?&gt;\s*&lt;/\1\s*&gt;/gixsm

我用http://gskinner.com/RegExr/http://regexpal.com/ 对其进行了测试,效果很好。 但是当我尝试运行它时。服务器总是返回错误:

Warning: preg_replace(): Unknown modifier '\'

我不知道究竟是什么'\'出了问题。有人请帮帮我!

【问题讨论】:

标签: php html regex


【解决方案1】:

在 php 正则表达式中,如果分隔符出现在表达式中,则需要转义它们。

在您的情况下,您有两个未转义的/;只需将它们替换为\/。你也不需要修饰符数组——php默认是全局的,你没有定义文字字符。

之前:

/<(\w+)\b(?:\s+[\w\-.:]+(?:\s*=\s*(?:"[^"]*"|"[^"]*"|[\w\-.:]+))?)*\s*/?>\s*</\1\s*>/gixsm

之后:

/<(\w+)\b(?:\s+[\w\-.:]+(?:\s*=\s*(?:"[^"]*"|"[^"]*"|[\w\-.:]+))?)*\s*\/?>\s*<\/\1\s*>/
//                                                                    ^       ^

【讨论】:

  • 另外,删除g 修饰符。 PCRE 默认是全局的。
  • 您可以删除所有修饰符。
  • @CasimiretHippolyte 确实,因为没有定义文字字母。
  • 谢谢大家!这是我的坏事。我是 RegEx 的新手,很难接近。
  • @MạnhHaiLúa 很高兴看到一些努力已经解决了这个问题;)
【解决方案2】:

此模式能够删除“空标签”(即不包含任何内容、空格、html cmets 或其他“空标签”的非自闭合标签),即使这些标签像 &lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt; 一样嵌套。不考虑html cmets中的标签:

$pattern = <<<'EOD'
~
<
(?:
    !--[^-]*(?:-(?!->)[^-]*)*-->[^<]*(*SKIP)(*F) # skip comments
  |
    ( # group 1
        (\w++)     # tag name in group 2
        [^"'>]* #'"# all that is not a quote or a closing angle bracket
        (?: # quoted attributes
            "[^\\"]*(?:\\.[^\\"]*)*+" [^"'>]* #'"# double quote
          |
            '[^\\']*(?:\\.[^\\']*)*+' [^"'>]* #'"# single quote
        )*+
        >
        \s*
        (?:
            <!--[^-]*(?:-(?!->)[^-]*)*+--> \s* # html comments
          |
            <(?1) \s*                          # recursion with the group 1
        )*+
        </\2> # closing tag
    ) # end of the group 1
)
~sxi
EOD;

$html = preg_replace($pattern, '', $html);

限制:

  • 此方法将删除指向外部 Javascript 文件的链接:
    &lt;script src="myscript.js"&gt;&lt;/script&gt;
  • 如果发现类似:
    var myvar="&lt;span&gt;&lt;/span&gt;";
    或类似:
    var myvar1="<span><!--"; function doSomething() { alert("!!!"); } var myvar2="--></span>";
    的内容,该模式可能会删除部分嵌入的 Javascript 代码。

这些限制是由于基本的文本方法无法区分 html 和 javascript 代码。但是,如果在模式跳过列表中添加“脚本”标签(与 html cmets 相同),则可以解决此问题,但在这种情况下,您需要基本描述 Javascript 内容(字符串、cmets、文字模式,所有这不是前三个)这不是一项微不足道的任务,而是可能的。

【讨论】:

  • 绝对比我的好!非常棒且乐于助人!谢谢!
  • 有什么方法可以让它在 PHP 5.3 (PCRE 8.12 2011-01-15) 上运行?它似乎不匹配任何东西,而在正则表达式测试站点(phpliveregex 或 regex101)上一切正常
  • @MarkL:没有理由该模式不适用于 php 5.3 及其相应的 PCRE 版本,您可能遗漏了一些东西,我建议在您的代码开头添加 ini_set('display_errors', 'On');走着瞧吧。不管怎样,我都会尽快改进这个答案。
  • 无法让它工作。 3 台不同的服务器,各种版本的 PHP/PCRE。启用错误显示。产生一个空值的数组。 phpliveregex.com 虽然有效。在这里拉头发。示例代码:pastie.org/10310797 如果我逐字使用您的代码(带有 EOD 等),它可以工作。什么给了?
  • @MarkL:您的问题与如何根据引号计算字符串中的文字反斜杠有关。请参阅eval.in/405609 和有关字符串和八进制数的 php 手册。
【解决方案3】:

删除空元素...以及下一个空元素。

体育

<p>Hello!
   <div class="foo"><p id="nobody">
   </p>
      </div>
 </p>

结果:

<p>Hello!</p>

php代码:

/* $html store the html content */
do {
    $tmp = $html;
    $html = preg_replace( '#<([^ >]+)[^>]*>([[:space:]]|&nbsp;)*</\1>#', '', $html );
} while ( $html !== $tmp );

【讨论】:

  • 确实不错!对于终极杀手空间进化,也可以试试这个:'#&lt;([^ &gt;]+)[^&gt;]*&gt;([[:space:]]|&amp;nbsp;)*&lt;/\1&gt;#'
【解决方案4】:

不太确定这是否是您需要的,但我今天找到了。你需要 PHP 5.4+!

$oDOMHTML = DOMDocument::loadHTML( 
    $sYourHTMLString, 
    LIBXML_HTML_NOIMPLIED | 
    LIBXML_HTML_NODEFDTD | 
    LIBXML_NOBLANKS | 
    LIBXML_NOEMPTYTAG 
);
$sYourHTMLStringWithoutEmptyTags = $oDOMHTML->saveXML();

也许这对你有用。

【讨论】:

  • 我试过了,但没有用。我的 PHP 是 5.4.19。稍后我会尝试(当我理解时)。谢谢!
  • 也许你给我一些示例代码,这只是编写没有任何测试。今天下午刚刚阅读了 LIBXML_* 常量。
  • 嗯,显然这些选项只是将“
    ”变成了“
    ”。 “”->“”也是如此。抱歉,我认为这可能会有所帮助。值得一试。
【解决方案5】:

您也可以使用递归来解决这个问题。继续将 HTML blob 传递回函数,直到不再存在空标记。

public static function removeHTMLTagsWithNoContent($htmlBlob) {
    $pattern = "/<[^\/>][^>]*><\/[^>]+>/";

    if (preg_match($pattern, $htmlBlob) == 1) {
        $htmlBlob = preg_replace($pattern, '', $htmlBlob);
        return self::removeHTMLTagsWithNoContent($htmlBlob);
    } else {
        return $htmlBlob;
    }
}

这将检查是否存在空 HTML 标记并替换它们,直到正则表达式模式不再匹配为止。

【讨论】:

    【解决方案6】:

    这是删除所有空标签的另一种方法。 (如果它们因为空子而被认为是空的,它也会删除周围的标签:

    /**
     * Remove empty tags.
     * This one will also remove <p><a href="/foo/bar.baz"><span></span></a></p> (empty paragraph with empty link)
     * But it will not alter <p><a href="/foo/bar.baz"><span>[CONTENT HERE]</span></a></p> (since the span has content)
     *
     * Be aware: <img ../> will be treated as an empty tag!
     */
    do
    {
        $len1 = mb_strlen($string);
        $string = preg_replace('/<(\w+)\b(?:\s+[\w\-.:]+(?:\s*=\s*(?:"[^"]*"|"[^"]*"|[\w\-.:]+))?)*\s*\/?>\s*<\/\1\s*>/', '', $string);
        $len2 = mb_strlen($string);
    
    } while ($len1 > 0 && $len2 > 0 && $len1 != $len2);
    

    我一直在使用它来清理来自外部 CMS 的 html,并取得了积极的结果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-01-18
      • 1970-01-01
      • 1970-01-01
      • 2020-08-29
      • 1970-01-01
      • 2012-02-22
      • 2017-06-19
      相关资源
      最近更新 更多