正则表达式删除所有空的 HTML 标记

Posted

技术标签:

【中文标题】正则表达式删除所有空的 HTML 标记【英文标题】:Regex to remove all empty HTML tags 【发布时间】: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 '\'

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

【问题讨论】:

How to remove only html tags in a string?的可能重复 很抱歉,我想删除不包含任何内容的 HTML 标签。这不是strip_tags 所做的。 【参考方案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,并取得了积极的结果。

【讨论】:

以上是关于正则表达式删除所有空的 HTML 标记的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式替换以删除 html 标记之间的空格

通过正则表达式删除嵌套在多个 html 标记中的特定单词

Oracle 正则表达式 - 删除字符串中长度为 1 的字母标记之间的空格

构建正则表达式(RegEx)以提取 HTML 标记的文本 [重复]

什么正则表达式将匹配文本,不包括 HTML 标记中的内容?

Notepad ++中的正则表达式删除空行