代码之家  ›  专栏  ›  技术社区  ›  core

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

  •  3
  • core  · 技术社区  · 15 年前

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

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

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

    7 回复  |  直到 15 年前
        1
  •  6
  •   Pesto    15 年前

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

        2
  •  2
  •   Karl    15 年前

    是的,它需要递归处理,而且可能相当深(当然也可能是一个奇特的循环),它不会用正则表达式来完成。您可以制作一个处理几层深度的正则表达式,但不能只处理任何html文件。这是因为解析器必须记住在流中任何给定点打开的标记,而regex在这方面并不擅长。

    使用带有一些计数器的SAX解析器,或者使用带有弹出/按下的堆栈来保持状态。想一想如何编写这个游戏,看看我说的html标记深度是什么意思。 http://en.wikipedia.org/wiki/Tower_of_Hanoi

        3
  •  1
  •   Vdex    15 年前

    如果您希望通过编程修复HTML,我使用了一个名为 html tidy 取得了相当大的成功。大多数语言(COM+、Dotnet、PHP等)都有它的版本。

        4
  •  1
  •   sebasgo    15 年前

    不,这对于正则表达式来说太复杂了。您的问题相当于测试一个正确使用括号的算术表达式,它至少需要一个 pushdown automaton 为了成功。

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

        5
  •  1
  •   ariddell    14 年前

    我有个案子 <[^/]+$ 哪个匹配一个“ < “然后是任何不是 / ".

        6
  •  1
  •   recalde    12 年前

    您可以使用正则表达式来标识所有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;
    }
    
        7
  •  0
  •   Laurynas    14 年前

    我建议使用 Nokogiri :

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