我知道你在想什么 - “噢,我的上帝,认真,不再” - 但请耐心等待,我的问题不仅仅是标题。在我们开始之前,我保证永远不会尝试使用正则表达式解析任意HTML,或者问其他人如何。
这里解释为什么你不能这样做的所有许多答案都依赖于正则表达式的正式定义。它们解析常规语言,HTML是无上下文但不是常规的,所以你不能这样做。但我也听说过各种语言的许多正则表达式实现都不是严格规范的;他们带来了超出正式正则表达范围的额外技巧。
由于我不知道任何特定实现的细节,例如perl,我的问题是:
答案 0 :(得分:12)
你的问题的答案是是,所谓的“扩展正则表达式” - 这可能比正式意义上的正则表达式更恰当地称为模式 - 例如在Perl和PCRE中找到的那些是indeed capable of recursive descent parsing of context-free grammars。
This posting’s对方法说明了将正则表达式应用于X / HTML并不是一个理论上的实际限制。在那里给出的第一种方法,即标记为天真的方法,更像是在大多数进行此类尝试的程序中易于找到的那种方法。这可以用于定义明确的非通用X / HTML,通常只需很少的努力。这是最好的应用程序,就像开放式X / HTML是最糟糕的。
标记为向导的第二种方法使用实际语法进行解析。因此,它与任何其他语法方法一样强大。然而,它也远远超出了绝大多数临时程序员的能力。它还有可能为了消极的利益重新创造一个完美的精细轮。我写这篇文章是为了表明可以做什么,但实际上在任何情况下都不应该。我想向人们展示为什么他们想要在开放式X / HTML上使用解析器,向他们展示即使使用当前可用的一些最强大的模式匹配工具,甚至接近正确也是如此艰难。
许多人误读我的帖子,因为某种方式提倡与我实际说的相反。请不要搞错:我说它使用起来太复杂了。这是反例的证明。我曾希望通过展示如何使用正则表达式来实现,人们会意识到为什么他们不想要走这条路。虽然一切皆有可能,但并非所有事情都是权宜之计。
我个人的经验法则是,如果所需的正则表达式只是第一类,我可能会使用它,但如果需要对第二类进行完全语法处理,我会使用别人已经编写的解析器。所以,即使我可以编写一个解析器,我也没有理由这样做,而且还有很多不这样做。
如果为明确的目的精心设计,模式可以比畸形的X / HTML更能抵抗现成的解析器,特别是如果你没有真正的机会攻击说解析器使它们能够更好地适应Web浏览器容忍的常见故障情况,但验证器却不会。但是,我上面提供的语法模式只是为了格式良好但合理的通用HTML而设计的(尽管没有实体替换,很容易添加)。解析器中的错误恢复完全是一个单独的问题,绝不是一个令人愉快的问题。
模式,特别是大多数人习惯看到和使用的更常见的非语法模式,更适合一次抓取一个离散的块,而不是用于生成完整的句法分析。换句话说,正则表达式对于lexing而言通常比解析更好。如果没有语法正则表达式,则不应尝试解析语法。
但是不要太过分了。我当然不是故意暗示你应该立即转向一个完整的解析器只是因为你想要处理递归定义的东西。这种事情中最简单也许最常见的例子是检测嵌套项目的模式,如括号。对我来说,在我的代码中简单地删除这样的东西是非常普遍的,并且完成它:
# delete all nested parens
s/\((?:[^()]*+|(?0))*\)//g;
答案 1 :(得分:2)
是的,问题中的扩展是反向引用,并且它们在技术上使“regexps”NP完全,请参阅Wikipedia paragraph。