【问题标题】:Can extended regex implementations parse HTML?扩展的正则表达式实现可以解析 HTML 吗?
【发布时间】:2011-06-23 10:43:44
【问题描述】:

我知道你在想什么——“我的天,说真的,不要再说了”——但请耐心等待,我的问题不仅仅是标题。在我们开始之前,我保证我永远不会尝试使用正则表达式解析任意 HTML,或者询问其他人如何。

这里有很多很多的答案来解释为什么你不能这样做,这依赖于正则表达式的正式定义。他们解析常规语言,HTML 是上下文无关的但不是常规的,所以你不能这样做。但我也听说各种语言的许多正则表达式实现都不是严格规则的;它们带有超出正式正则表达式范围的额外技巧。

由于我不知道任何特定实现的细节,例如 perl,我的问题是:

  1. 正则表达式工具的哪些功能是非常规的?是后面的引用吗?它们是用哪些语言找到的?
  2. 这些额外的技巧是否足以解析所有上下文无关语言?
  3. 如果对#2 表示“否”,那么这些额外功能是否完全涵盖了正式的语言类别或类别?我们如何才能快速知道我们试图解决的问题是否在我们的非正则表达式的能力范围内?

【问题讨论】:

  • 天哪,说真的,不会再来了

标签: regex


【解决方案1】:

您的问题的答案是是的,所谓的“扩展正则表达式”——在正式意义上,它们可能比正则表达式更恰当地称为模式——例如在 Perl 和 PCRE 中发现的那些是indeed capable of recursive descent parsing of context-free grammars

This posting’s 这对方法说明了将正则表达式应用于 X/HTML 的理论限制而非实际限制。那里给出的第一种方法,被标记为 naïve 的方法,更像是你在大多数进行这种尝试的程序中容易找到的那种方法。这可以在定义明确的非通用 X/HTML 上工作,通常只需很少的努力。这是它最好的应用程序,就像开放式 X/HTML 是它最糟糕的应用程序一样。

第二种方法,标记为wizardly,使用实际语法进行解析。因此,它与任何其他语法方法一样强大。然而,它也远远超出了绝大多数休闲程序员的能力。它还冒着为负面利益重新创造一个完美的轮子的风险。我写它是为了说明可以做什么,但实际上在任何情况下不应该做什么。我想向人们展示他们为什么要在开放式 X/HTML 上使用解析器,通过向他们展示即使使用目前可用的一些最强大的模式匹配工具也很难接近正确。

许多人误读了我的帖子,认为它在某种程度上提倡与我实际所说的相反。请不要误会:我是说它使用起来太复杂了。这是一个反例证明。我曾希望通过展示如何使用正则表达式来做到这一点,人们会意识到为什么他们想要走这条路。虽然一切皆有可能,但并非一切都是权宜之计。

我个人的经验法则是,如果所需的正则表达式仅属于第一类,我可能会使用它,但如果它需要对第二类进行完全语法处理,我会使用其他人已经编写的解析器。所以即使我可以写一个解析器,我认为没有理由这样做,而且还有很多不这样做。

当为该明确目的精心设计时,模式可以比现成的解析器更容易适应格式错误的 X/HTML,特别是如果你没有真正的机会破解所说的解析器使它们对 Web 浏览器倾向于容忍但验证器不能容忍的常见故障情况更具弹性。但是,我在上面提供的语法模式仅适用于格式良好但相当通用的 HTML(尽管没有实体替换,这很容易添加)。解析器中的错误恢复完全是一个单独的问题,绝不是一个令人愉快的问题。

模式,尤其是大多数人习惯于看到和使用的更为常见的非语法模式,更适合一次抓取一个离散的块,而不是生成完整的句法分析。换句话说,正则表达式在词法分析方面通常比在解析方面更有效。没有语法正则表达式,你不应该尝试解析语法。

但不要走得太远。我当然不是暗示你应该立即转向成熟的解析器,只是因为你想处理递归定义的东西。这类事情最简单也是最常见的例子是检测嵌套项的模式,比如括号。对我来说,在我的代码中简单地写下类似这样的简单内容并完成它是非常常见的:

# delete all nested parens
s/\((?:[^()]*+|(?0))*\)//g;

【讨论】:

    【解决方案2】:

    是的,问题中的扩展是反向引用,它们在技术上使“正则表达式”NP-complete,请参阅Wikipedia paragraph

    【讨论】:

    • NP-completeness 是指计算复杂度,而不是解析能力。我认为这是该页面中的错误,就像发布此答案时一样。当前版本似乎已经修复了它 - 现在说它们能够解析上下文相关的语言。
    猜你喜欢
    • 2015-11-28
    • 1970-01-01
    • 2021-07-20
    • 2014-12-06
    • 2012-09-12
    • 2014-05-16
    • 1970-01-01
    • 2016-09-26
    • 2014-06-08
    相关资源
    最近更新 更多