正则表达式为未关闭的HTML标记

时间:2009-08-03 17:58:51

标签: html regex

是否有人使用正则表达式匹配未关闭的HTML标记?例如,正则表达式将匹配<b>和第二个<i>,但不匹配第一个<i>或第一个结束</i>标记:

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

这对正则表达式来说太复杂了吗?可能需要一些递归的,程序化的处理吗?

7 个答案:

答案 0 :(得分:6)

我确信一些正则表达式大师可以将一些近似于解决方案的东西拼凑在一起,但这是一个坏主意:HTML isn't regular。考虑一个能够识别此类问题的HTML解析器,或者自己解析它。

答案 1 :(得分:2)

是的,它需要递归处理,并且可能非常深(或者当然是一个花哨的循环),它不会用正则表达式来完成。你可以创建一个处理几个级别的正则表达式,但不能只处理任何html文件。这是因为解析器必须记住在流中任何给定点打开的标记,并且正则表达式并不擅长。

对某些计数器使用SAX解析器,或使用弹出/推入的堆栈来保持状态。考虑如何编码这个游戏,看看我对html标签深度的意义。 http://en.wikipedia.org/wiki/Tower_of_Hanoi

答案 2 :(得分:1)

正如@Pesto所说,HTML不是常规的,你必须构建html语法规则,并递归地应用它们。

如果您希望以编程方式修复HTML,我使用了一个名为html tidy的组件并取得了相当大的成功。大多数语言都有它的构建(COM +,Dotnet,PHP等...)。

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

答案 3 :(得分:1)

不,这对于正则表达式来说很复杂。您的问题等同于测试正确使用括号的算术表达式,这需要至少pushdown automaton成功。

在您的情况下,您应该在开始标记,结束标记和文本节点中拆分HTML代码(例如使用正则表达式)。将结果存储在列表中。然后,您可以遍历节点列表并将每个开始标记推送到堆栈。如果在节点列表中遇到结束标记,则必须检查最顶层的堆栈条目是否为相同类型的开始标记。否则,您找到了您查找的html语法错误。

答案 4 :(得分:1)

我有一个案例,我处理单个,自包含的行。以下正则表达式适用于我:<[^/]+$匹配“<”,然后匹配任何不是“/”。

答案 5 :(得分:1)

您可以使用RegEx识别所有html开始/结束元素,然后使用Stack枚举,推送新元素和弹出结束标记。在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;
}

答案 6 :(得分:0)

我建议使用Nokogiri

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