似乎在stackoverflow上的每个问题中,提问者使用regex从HTML中获取一些信息,将不可避免地有一个“答案”,说不要使用regex解析HTML。

为什么不呢?我知道有一些所谓的“真正的”HTML解析器,比如Beautiful Soup,我相信它们是强大而有用的,但如果您只是在做一些简单、快速或简单的事情,那么当一些正则表达式语句就可以很好地工作时,为什么要麻烦使用如此复杂的东西呢?

此外,是否只是因为我不理解正则表达式的某些基本原理,才使得它们在解析中成为一个糟糕的选择?


当前回答

对于快速´n´dirty regexp就可以了。但是要知道的基本问题是,不可能构造一个正确解析HTML的regexp。

原因是regexp不能处理任意嵌套的表达式。参见正则表达式能否用于匹配嵌套模式?

其他回答

问题是,大多数用户问的问题都与HTML和正则表达式有关,因为他们找不到自己的正则表达式。然后,必须考虑使用DOM或SAX解析器或类似的东西是否会更容易一些。它们是为处理类似xml的文档结构而优化和构造的。

当然,有些问题可以用正则表达式轻松解决。但重点在于容易。

如果您只想找到所有看起来像http://.../的url,那么使用regexp是没问题的。但是如果你想要找到a- element中所有具有'mylink'类的url,你可能最好使用合适的解析器。

两个简单的原因:

编写一个能够抵御恶意输入的正则表达式是困难的;比使用预先构建的工具难多了 编写一个正则表达式来处理你不可避免地会遇到的荒谬的标记是困难的;比使用预先构建的工具难多了

关于正则表达式在解析中的适用性:它们并不合适。您是否见过解析大多数语言所需的正则表达式类型?

(来自http://htmlparsing.com/regexes)

假设您有一个HTML文件,您试图从中提取url < img >标签。

<img src="http://example.com/whatever.jpg">

所以你可以用Perl写一个这样的正则表达式:

if ( $html =~ /<img src="(.+)"/ ) {
    $url = $1;
}

在本例中,$url确实包含 http://example.com/whatever.jpg。但是当 你会得到这样的HTML:

<img src='http://example.com/whatever.jpg'>

or

<img src=http://example.com/whatever.jpg>

or

<img border=0 src="http://example.com/whatever.jpg">

or

<img
    src="http://example.com/whatever.jpg">

否则你就会得到假阳性

<!-- // commented out
<img src="http://example.com/outdated.png">
-->

它看起来很简单,对于一个单一的、不变的文件来说可能很简单,但是对于任意HTML数据,正则表达式只会让你将来头疼。

正则表达式无法解析整个HTML,因为它依赖于匹配开始标记和结束标记,而正则表达式则无法匹配。

正则表达式只能匹配常规语言,但HTML是一种与上下文无关的语言,而不是常规语言(正如@StefanPochmann所指出的,常规语言也是与上下文无关的,因此与上下文无关并不一定意味着不常规)。在HTML上使用regexp唯一能做的事情是启发式,但这并不适用于所有条件。任何正则表达式都可以错误地匹配HTML文件。

因为有很多方法可以“搞砸”HTML,浏览器会以一种相当自由的方式对待它们,但要用正则表达式重现浏览器的自由行为来覆盖所有情况需要相当大的努力,所以你的正则表达式将不可避免地在某些特殊情况下失败,这可能会在你的系统中引入严重的安全漏洞。