删除所有空HTML标记?

Sve*_*ang 1 .net regex recursion html-parsing recursive-regex

我想象一个函数,我想使用正则表达式,它将是递归的实例,如<p><strong></strong></p>删除字符串中的所有空HTML标记.如果可能的话,这必须考虑空白.没有疯狂的实例,其中<character在属性值中使用.

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

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

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
Run Code Online (Sandbox Code Playgroud)

但是我现在的正则表达式是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*>", "")

rid*_*ner 8

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

更新:下面的解决方案现在递归地应用空元素正则表达式来删除"嵌套空元素"结构,例如:( <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
Run Code Online (Sandbox Code Playgroud)

增强版

<(\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
Run Code Online (Sandbox Code Playgroud)

这个更复杂的正则表达式正确匹配有效的空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);
    }
}
Run Code Online (Sandbox Code Playgroud)

注意事项:此函数不解析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解析器!