1

我正在想象一个我认为将使用正则表达式的函数,并且对于像<p><strong></strong></p>删除字符串中的所有空 HTML 标记这样的实例来说,它将是递归的。如果可能的话,这将不得不考虑空格。不会有在属性值中使用 < 字符的疯狂实例。

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

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

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 标记与任意数量的属性、一个空标记(例如 just <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

4 回答 4

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

增强版

<(\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 解析器!

于 2011-04-06T21:22:31.320 回答
1

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

于 2011-04-06T20:00:53.127 回答
1

你不能用正则表达式来做到这一点。假设 html 格式正确,您可能会使用 xml 解析器。

于 2011-04-06T20:03:39.083 回答
0

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

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

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

于 2011-04-06T20:04:14.530 回答