HTMLparsing如果不使用正则expression式,如何工作?
我每天都会看到一些问题,询问如何从某个HTMLstring中parsing或提取某些东西,而第一个答案/注释总是“不要使用RegEx来parsingHTML,以免感到愤怒! (最后一部分有时被省略)。
这对我来说相当困惑,我一直认为一般来说,parsing任何复杂string的最好方法是使用正则expression式。 那么HTMLparsing器如何工作呢? 它不使用正则expression式来parsing。
使用正则expression式的一个特别的参数是,并不总是有一个parsing的select(比如JavaScript,其中DOMDocument不是一个普遍可用的选项)。 例如,jQuery似乎使用正则expression式来将HTMLstring转换为DOM节点。
不知道是否要CW,这是一个真正的问题,我想回答,而不是真的打算成为一个讨论的线索。
通常通过使用一个记号器。 草案HTML5规范有一个广泛的algorithm来处理“现实世界的HTML”。
那么HTMLparsing器是如何工作的呢? 不使用正则expression式来parsing吗?
那么,不。
如果你重新回到计算过程的理论,如果你拿一个,或编译器的课程,或类似的东西,你可能会记得,有不同种类的语言和计算模型。 我没有资格详细介绍所有的细节,但是我可以和您一起回顾一些主要观点。
最简单的语言和计算types(为了这些目的)是一种常规语言。 这些可以用正则expression式生成,并用有穷自动机来识别。 基本上,这意味着“parsing”这些语言的string使用状态,而不是辅助内存。 HTML肯定不是一种常规的语言。 如果你仔细想想,标签列表可以任意嵌套。 例如,表格可以包含表格,每个表格可以包含大量的嵌套标签。 使用正则expression式,您可能能够挑选出一对标签,但不能任意嵌套任何东西。
不规则的经典简单语言是正确匹配的括号。 尽可能地尝试,你将永远无法build立一个总能正常工作的正则expression式(或有穷自动机)。 你需要记忆来追踪嵌套深度。
具有内存堆栈的状态机是计算模型的下一个优势。 这被称为下推式自动机,它识别由上下文无关文法产生的语言。 在这里,我们可以识别正确匹配的圆括号 – 实际上,堆栈是它的完美记忆模型。
那么,这是不够的HTML? 可悲的是,不。 也许对于经过严格validation的XML来说,实际上,所有的标签总是完美地排列起来。 在真实世界的HTML中,您可以轻松find像<b><i>wow!</b></i>
这样的片段。 这显然不能嵌套,所以为了正确parsing它,一个堆栈不够强大。
下一级计算是由一般语法生成的语言,并由图灵机识别。 这被普遍认为是最强有力的计算模型 – 一个状态机,具有辅助存储器,其存储器可以在任何地方修改。 这是编程语言可以做的。 这是HTML生活的复杂程度。
用一句话来概括一切:为了parsing一般的HTML,你需要一个真正的编程语言,而不是一个正则expression式。
HTMLparsing的方式与parsing其他语言的方式相同:lexing和parsing。 lexing步骤将单个字符stream分解成有意义的记号。 parsing步骤将使用状态和内存的令牌组装成逻辑上一致的文档,可以对其执行操作。
正则expression式只是parsing器的一种forms。 一个诚实善良的HTMLparsing器将比正则expression式复杂得多,使用recursion下降 ,预测和其他几种技术来正确解释文本。 如果你真的想进入它,你可以看看lex&yacc和类似的工具。
禁止使用正则expression式进行HTMLparsing应该更正确地写成:“不要使用朴素的正则expression式来parsingHTML …” (以免让人感到愤怒) “…并谨慎处理结果。 对于某些特定的目标,正则expression式可能是完全适合的,但是你需要非常小心地注意到你的正则expression式的局限性,并且要谨慎,以适应你正在parsing的文本的来源(例如,如果它用户input,确实要非常小心)。
parsingHTML是将线性文本转换为树形结构。 正则expression式通常不能处理树结构。 您每次获得下一个标记所需的正则expression式始终在变化。 您可以在parsing器中使用正则expression式,但是每个可能的parsing状态都需要一整套正则expression式。
如果你想有一个100%的解决scheme:你需要编写你自己的自定义代码,逐个字符地遍历HTML,你需要有大量的逻辑来确定你是否应该停止当前节点并启动下一个。
原因是这是有效的HTML:
<ul> <li>One <li>Two <li>Three </ul>
但是这样的:
<ul> <li>One</li> <li>Two</li> <li>Three</li> </ul>
如果你确定“90%的解决scheme”:然后使用XMLparsing器来加载文件是好的。 或者使用Regex(尽pipe如果你是内容的主人,xml会更容易)。