正则表达式真的不能解析 HTML 吗?
The true power of regular expressions (2012)
在 StackOverflow 的 PHP 标签下,常有人被劝告不要用正则表达式解析 HTML,理由是 HTML 不是正则语言。但这其实是个误解。现代正则表达式引擎(如 PCRE)早已超越了形式语言理论中的“正则”定义。通过递归子模式等特性,它们不仅能匹配正则语言,还能处理上下文无关语言,甚至能优雅地表达像 RFC 5322 邮箱地址这样复杂的语法规则。虽然正则表达式擅长匹配,但在构建抽象语法树方面仍有局限,但这并不妨碍它成为解析复杂文本的强大工具。
当程序员谈论“正则表达式”时,他们指的不是形式文法,而是其语言实现的正则表达式衍生版本。
HN 评论区
61- jakobnissen
这篇文章具有误导性,因为它将正则表达式与 PCRE 等具体实现混为一谈,而后者也支持非正则的字符串匹配。
令人恼火的是,这篇文章很好地解释了什么是正则表达式,以及相对于 PCRE 而言正则表达式的局限性,所以作者应该明白,当他们谈论 NP 完全的字符串匹配时,指的不是正则表达式,而是 PCRE 特有的功能。
这种区分很重要,因为正则表达式绝对无法匹配 HTML,而且与 PCRE 表达式不同,正则表达式在匹配长度为 n 的字符串时,具有保证的 O(1) 空间复杂度和 O(n) 时间复杂度。当你使用 PCRE 功能进行字符串匹配时,复杂度可能会退化为指数级,使其变得毫无用处。例如,你可以发起针对 PCRE 的拒绝服务攻击,但无法发起针对正则表达式的拒绝服务攻击(除非你能用几兆字节大小的正则表达式进行查询)。
- AussieWog93
可能只是我个人的问题,但我一直对正则表达式心存戒备。写起来倒也不算太难,但回过头来阅读并理解到底发生了什么,有时会变得相当棘手。此外,各个正则表达式库之间那些微妙的差异,感觉就像是一颗颗埋好的地雷。
显然它们有存在的价值,但我知道很多老一辈的开发者似乎比年轻人更钟爱它们。
- cadamsdotcom
有些人面对问题时,会想:"我知道,我让我的代理人用正则表达式来解决它。"
于是他们现在有三个问题了。
- HelloUsername
"用正则表达式写 Doom" https://news.ycombinator.com/item?id=49094081
- lbriner
有些看似显而易见但人们评论时未必点明的一点是:很少有人试图用正则表达式匹配整个文档,所以"HTML 不是正则语言"这一点其实并不重要。
如果我试图用类似 "<div" 的正则表达式来统计 div 标签的数量,那么显然这在 99.9% 的情况下都能行得通,并且很可能达到发帖人想要的效果。
一旦你加上字符类来忽略文档中不关心的部分,比如 "<div[^>]*>" 之类的,那么即使被忽略的部分不完全符合正则语言,它依然非常有用。
正则表达式的一个美妙之处在于它的速度。有人让我解析一个巨大的 CAN 总线日志文件,统计某个事件发生的次数。那是 2000 年代初,文件有 6GB,在当时算很大了。我试过 .Net 的 string.StartsWith 之类的功能,跑完整个文件花了好长时间。我用正则表达式做了同样的事,结果大概 5 秒就搞定了(用的是 HDD,不是 SSD!)。我不知道其中的魔法是如何运作的,但确实令人印象深刻。