删除所有空HTML标记?

时间:2011-04-06 19:56:59

标签: .net regex recursion html-parsing recursive-regex

我正在想象一个我想要使用Regex的函数,对于像<p><strong></strong></p>这样的实例来说,删除字符串中的所有空HTML标签会是递归的。如果可能的话,这必须考虑空白。没有疯狂的实例&lt;字符正在属性值中使用。

我在正则表达式上非常糟糕,但我想这是可能的。你怎么能这样做?

这是我到目前为止的方法:

Public Shared Function stripEmptyHtmlTags(ByVal html As String) As String
    Dim newHtml As String = Regex.Replace(html, "/(<.+?>\s*</.+?>)/Usi", "")

    If html <> newHtml Then
        newHtml = stripEmptyHtmlTags(newHtml)
    End If

    Return newHtml
End Function

然而,我现在的正则表达式是PHP格式,它似乎不起作用。我不熟悉.NET正则表达式语法。

对于所有那些不使用正则表达式的人:我很好奇这种模式无论如何。当然有一种模式可以匹配所有打开/关闭开始标签与标签之间的任何数量的空白(或没有)?我已经看到正则表达式将HTML标记与任意数量的属性匹配,一个空标记(例如只是<p></p>)等。

到目前为止,我已经在上面的方法中尝试了以下正则表达式模式无效(因为,我有一个带有空段落标记的文本字符串,甚至没有被删除。)

Regex.Replace(html, "/(<.+?>\s*</.+?>)/Usi", "")

Regex.Replace(html, "(<.+?>\s*</.+?>)", "")

Regex.Replace(html, "%<(\w+)\b[^>]*>\s*</\1\s*>%", "")

Regex.Replace(html, "<\w+\s*>\s*</\1\s*>", "")

4 个答案:

答案 0 :(得分:8)

首先,请注意,根据定义,空HTML元素不是嵌套的。

更新:下面的解决方案现在递归地应用空元素正则表达式来删除“nested-empty-element”结构,例如:<p><strong></strong></p>(受制于注意事项如下所述。)

简单版本:

对于没有包含<>有趣内容的开始标记属性的HTML,以(未经测试的)VB.NET片段的形式,这非常有效(请参阅下面的注意事项):

Dim RegexObj As New Regex("<(\w+)\b[^>]*>\s*</\1\s*>")
Do While RegexObj.IsMatch(html)
    html = RegexObj.Replace(html, "")
Loop

增强版

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

以下是VB.NET中未注释的增强版本(未经测试):

Dim RegexObj As New Regex("<(\w+)\b(?:\s+[\w\-.:]+(?:\s*=\s*(?:""[^""]*""|'[^']*'|[\w\-.:]+))?)*\s*/?>\s*</\1\s*>")
Do While RegexObj.IsMatch(html)
    html = RegexObj.Replace(html, "")
Loop

这个更复杂的正则表达式正确匹配有效的空HTML 4.01元素,即使它的属性值中有尖括号(再次提到主题,请注意下面的警告)。换句话说,这个正则表达式正确处理引用的所有开始标记属性值(可以有<>),不带引号(不能)和空。这是一个完全评论(和测试)的PHP版本:

function strip_empty_tags($text) {
    // Match empty elements (attribute values may have angle brackets).
    $re = '%
        # Regex to match an empty HTML 4.01 Transitional element.
        <                    # Opening tag opening "<" delimiter.
        (\w+)\b              # $1 Tag name.
        (?:                  # Non-capture group for optional attribute(s).
          \s+                # Attributes must be separated by whitespace.
          [\w\-.:]+          # Attribute name is required for attr=value pair.
          (?:                # Non-capture group for optional attribute value.
            \s*=\s*          # Name and value separated by "=" and optional ws.
            (?:              # Non-capture group for attrib value alternatives.
              "[^"]*"        # Double quoted string.
            | \'[^\']*\'     # Single quoted string.
            | [\w\-.:]+      # Non-quoted attrib value can be A-Z0-9-._:
            )                # End of attribute value alternatives.
          )?                 # Attribute value is optional.
        )*                   # Allow zero or more attribute=value pairs
        \s*                  # Whitespace is allowed before closing delimiter.
        >                    # Opening tag closing ">" delimiter.
        \s*                  # Content is zero or more whitespace.
        </\1\s*>             # Element closing tag.
        %x';
    while (preg_match($re, $text)) {
        // Recursively remove innermost empty elements.
        $text = preg_replace($re, '', $text);
    }
}

警告:此功能不解析HTML。它只是匹配并删除与有效的空HTML 4.01元素相对应的任何文本模式序列(根据定义,它是嵌套)。请注意,这也会错误地匹配并删除可能在普通HTML标记之外发生的相同文本模式,例如SCRIPT和STYLE标记和HTML注释以及其他开始标记的属性。此正则表达式不适用于短标签。对于任何bobenc粉丝,给这个答案一个自动向下投票,请告诉我一个有效的HTML 4.01空元素,这个正则表达式无法正确匹配。这个正则表达式遵循W3C规范,确实有效。

更新:如果您执行极其不可能(但完全有效),此正则表达式解决方案也无效(并且会错误地删除有效标记):

<div att="<p att='">stuff</div><div att="'></p>'">stuff</div>

要点:

再想一想,只需使用HTML解析器!

答案 1 :(得分:1)

您遇到的问题是任意级别的嵌套,无法与标准正则表达式匹配。我想你可以一遍又一遍地应用相同的正则表达式替换,直到没有留下任何东西。但是有更好的解决方案,例如专用的HTML解析库。

答案 2 :(得分:1)

你不能用正则表达式来做。假设html格式正确,你可以使用xml解析器。

答案 3 :(得分:0)

为什么递归,你可以简单地运行

 <(\w+)\s*>\s*</\1\s*>

并将其替换为空,并继续应用该正则表达式,直到您的输入不再更改为止。

相关问题