未闭合的HTML标签的正则表达式

3

有人有匹配未闭合的HTML标签的正则表达式吗?例如,该正则表达式将匹配<b>和第二个<i>,但不会匹配第一个<i>或第一个的结束标签</i>:

<i><b>test<i>ing</i>

这个需要使用正则表达式吗?可能需要一些递归的编程处理吗?
7个回答

6
我确信一些正则表达式大师可以拼凑出近似的解决方案,但这是个坏主意:HTML并不是正则的。考虑使用能够识别此类问题的HTML解析器,或自行解析。

4
很遗憾,SO没有API。我想象一下代码会是这样的:for (Question q : questionsTagged("regex", "html")) { q.addAnswer(new Answer("HTML不规则,所以正则表达式几乎从来不是一个好选择。")); } - Michael Myers
2
当然,如果原帖在问题中已经预先回答了这个问题,你看起来就会很傻,就像他在这里做的那样。 - Michael Myers
@mmyers:老实说,我就是忍不住想链接到Welbog的某个东西。 - Pesto

2
是的,它需要递归处理,可能会很深(或者使用一个高级的循环),这不可能通过正则表达式来完成。你可以制作一个能够处理几个层级的正则表达式,但不能处理任何HTML文件。这是因为解析器必须记住在流中任何给定点上打开的标签,而正则表达式并不擅长处理这种情况。
使用SAX解析器和一些计数器,或使用栈来保持状态。考虑编写这个游戏以了解我所说的HTML标记深度的含义。http://en.wikipedia.org/wiki/Tower_of_Hanoi

1

您可以使用正则表达式来识别所有的HTML开始/结束元素,然后使用堆栈枚举,推入新元素并弹出关闭标签。在C#中尝试一下:

public static bool ValidateHtmlTags(string html)
{
    string expr = "(<([a-zA-Z]+)\\b[^>]*>)|(</([a-zA-Z]+) *>)";
    Regex regex = new Regex(expr, RegexOptions.IgnoreCase);
    var stack = new Stack<Tuple<string, string>>();
    var result = new StringBuilder();
    bool valid = true;

    foreach (Match match in regex.Matches(html))
    {
        string element = match.Value;
        string beginTag = match.Groups[2].Value;
        string endTag = match.Groups[4].Value;

        if (beginTag == "")
        {
            string previousTag = stack.Peek().Item1;
            if (previousTag == endTag)
                stack.Pop();
            else
            {
                valid = false;
                break;
            }
        }
        else if (!element.EndsWith("/>"))
        {
            // Write more informative message here if desired
            string message = string.Format("Char({0})", match.Index);
            stack.Push(new Tuple<string, string>(beginTag, message));
        }
    }

    if (stack.Count > 0)
        valid = false;

    // Alternative return stack.Peek().Item2 for more informative message
    return valid;
}

1
我遇到了一种情况,需要处理单一的、独立的行。下面这个正则表达式对我有用:<[^/]+$,它匹配一个"<",然后是任何不是"/"的字符。

1

正如@Pesto所说,HTML并不规则,您需要构建HTML语法规则,并递归地应用它们。

如果您想通过编程方式修复HTML,我曾经使用过一个名为html tidy的组件,并取得了相当大的成功。对于大多数语言(COM+,Dotnet,PHP等),都有该组件的版本。

如果您只需要手动修复它,我建议使用一个好的IDE。Visual Studio 2008做得很不错,最新版本的Dreamweaver也不错。


1

不,这对于正则表达式来说太复杂了。你的问题相当于测试括号的正确使用的算术表达式,这需要至少一个下推自动机才能成功。

在你的情况下,你应该将HTML代码分割成开放标签、关闭标签和文本节点(例如使用正则表达式)。将结果存储在列表中。然后,您可以遍历节点列表并将每个开放标签推送到堆栈上。如果在节点列表中遇到一个关闭标签,则必须检查最顶部的堆栈条目是否是相同类型的开放标签。否则,您找到了您要查找的HTML语法错误。


0

我建议使用Nokogiri

  Nokogiri::HTML::DocumentFragment.parse(html).to_html

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接