提问人:Andy E 提问时间:3/8/2010 最后编辑:Martin.Andy E 更新时间:4/13/2012 访问量:6727
如果 HTML 解析不使用正则表达式,它们如何工作?
How do HTML parses work if they're not using regexp?
问:
我每天都会看到一些问题,询问如何从一些 HTML 字符串中解析或提取一些东西,第一个答案/评论总是“不要使用正则表达式来解析 HTML,以免你感到愤怒!(最后一部分有时会省略)。
这让我相当困惑,我一直认为,一般来说,解析任何复杂字符串的最佳方法是使用正则表达式。那么 HTML 解析器是如何工作的呢?它不是使用正则表达式来解析吗?
使用正则表达式的一个特殊论点是,并不总是有解析替代方案(例如 JavaScript,其中 DOMDocument 不是通用选项)。例如,jQuery 似乎可以很好地使用正则表达式将 HTML 字符串转换为 DOM 节点。
不确定是否要CW这个,这是一个真正的问题,我想得到回答,而不是真正打算成为一个讨论线程。
答:
如果你想有一个 100% 的解决方案:你需要编写自己的自定义代码,逐个字符迭代 HTML,你需要有大量的逻辑来确定你是否应该停止当前节点并启动下一个节点。
原因是这是有效的 HTML:
<ul>
<li>One
<li>Two
<li>Three
</ul>
但这也是:
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
</ul>
如果您对“90% 解决方案”感到满意:那么使用 XML 解析器加载文档就可以了。或者使用正则表达式(尽管如果您掌握了内容,则 xml 会更容易)。
评论
通常通过使用分词器。HTML5 规范草案有一个广泛的算法来处理“现实世界的 HTML”。
评论
正则表达式只是解析器的一种形式。一个诚实至善的 HTML 解析器将比在正则表达式中表达的复杂得多,它使用递归下降、预测和其他几种技术来正确解释文本。如果你真的想进入它,你可以看看lex和yacc和类似的工具。
禁止使用正则表达式进行 HTML 解析可能应该更正确地写成:“不要使用朴素的正则表达式来解析 HTML......”(免得你们感到忿怒)"...并谨慎对待结果。对于某些特定目标,正则表达式可能完全足够,但您需要非常小心地了解正则表达式的局限性,并尽可能谨慎地解析您正在解析的文本源(例如,如果是用户输入,请非常小心)。
评论
那么 HTML 解析器是如何工作的呢?它不是使用正则表达式来解析吗?
嗯,不。
如果你回到你的大脑中,如果你上了一门计算理论课程,或者一门编译器课程,或者类似的东西,你可能会记得有不同种类的语言和计算模型。我没有资格详细介绍,但我可以和你一起回顾一些要点。
最简单的语言和计算类型(用于这些目的)是常规语言。这些可以用正则表达式生成,也可以用有限自动机来识别。基本上,这意味着在这些语言中“解析”字符串使用状态,而不是辅助内存。HTML 当然不是一种常规语言。如果你仔细想想,标签列表可以任意嵌套。例如,表可以包含表,每个表可以包含大量嵌套标记。使用正则表达式,您也许可以挑选出一对标签,但肯定不能任意嵌套任何标签。
一种不规则的经典简单语言是正确匹配的括号。尽你所能,你永远无法构建一个永远有效的正则表达式(或有限自动机)。您需要内存来跟踪嵌套深度。
具有内存堆栈的状态机是计算模型的下一个优势。这称为下推自动机,它识别由上下文无关语法生成的语言。在这里,我们可以识别正确匹配的括号——事实上,堆栈是它的完美内存模型。
那么,这对 HTML 来说足够好吗?可悲的是,没有。也许对于超级骗子来说,实际上,经过仔细验证的XML,其中所有标签总是完美地排列在一起。在现实世界的 HTML 中,您可以轻松找到类似 .这显然没有嵌套,所以为了正确解析它,堆栈不够强大。<b><i>wow!</b></i>
下一个计算级别是由通用语法生成并由图灵机识别的语言。这被普遍认为是最强大的计算模型——一台带有辅助内存的状态机,其内存可以在任何地方修改。这就是编程语言可以做到的。这就是 HTML 所处的复杂程度。
用一句话总结这里的一切:要解析通用 HTML,您需要一种真正的编程语言,而不是正则表达式。
HTML 的解析方式与其他语言的解析方式相同:词法分析和解析。词法转换步骤将单个字符的流分解为有意义的标记。分析步骤使用状态和内存将标记组合成一个逻辑上一致的文档,可以对其进行操作。
解析 HTML 是将线性文本转换为树状结构。正则表达式通常不能处理树结构。获取下一个令牌所需的每个点的正则表达式一直在变化。您可以在解析器中使用正则表达式,但对于每种可能的解析状态,您将需要一整套正则表达式。
评论