Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex 解析HTML/XML文档是如何工作的?_Regex_Dom - Fatal编程技术网

Regex 解析HTML/XML文档是如何工作的?

Regex 解析HTML/XML文档是如何工作的?,regex,dom,Regex,Dom,有人告诉我,也经常看到别人告诉我:不要使用正则表达式来解析(或“解析”)用HTML、XML等语言编写的文档。命名的原因各不相同,在这里并不重要 当被问到该做什么时,通常会引用一个库来解析这样的文档——PHP扩展、JS框架等。大多数情况下,它们似乎依赖于文档对象模型 我的问题不是如何在程序或脚本中实现这一点。在实际情况下,我不会再尝试发明轮子,而只是使用一个可用的框架 我想知道的是——这些框架是如何做到的?或者,如果没有一个框架(假设),我该怎么做?我不是在具体谈论任何语言,我感兴趣的是从文档中提

有人告诉我,也经常看到别人告诉我:不要使用正则表达式来解析(或“解析”)用HTML、XML等语言编写的文档。命名的原因各不相同,在这里并不重要

当被问到该做什么时,通常会引用一个库来解析这样的文档——PHP扩展、JS框架等。大多数情况下,它们似乎依赖于文档对象模型

我的问题不是如何在程序或脚本中实现这一点。在实际情况下,我不会再尝试发明轮子,而只是使用一个可用的框架


我想知道的是——这些框架是如何做到的?或者,如果没有一个框架(假设),我该怎么做?我不是在具体谈论任何语言,我感兴趣的是从文档中提取信息背后的理论。

解析XML需要一种能够识别称为“上下文无关语言”的工具。正则表达式识别正则语言,这是上下文无关语言的一个子集

识别常规语言

规则语言由确定性有限自动机(DFAs)识别。DFA是一组状态,状态之间有过渡边,还有一个输入缓冲区(正在解析的字符串)。DFA在其启动状态下开始。DFA读取输入缓冲区开头的字符,告诉它要进行哪个转换。这会将DFA移动到下一个状态,在该状态下重复该过程。如果DFA遇到没有转换的输入字符,它将结束(输入无法识别)。如果DFA达到指定的结束状态,则输入已被识别

要记住的最重要的一点是,DFA不记得他们去过哪些州——只记得他们现在在哪里,下一步要去哪里。这使得DFA无法识别某些类型的语言,例如匹配的XML标记

正则表达式实现(如PCRE)有一些方便的扩展(例如“+”、“?”和字符类),还有一些更改正则表达式功能的扩展(如前向和后向引用)。这些正则表达式比DFA功能更强大,但仅使用这些扩展正则表达式构建XML解析器是很困难或不可能的

识别上下文无关语言

上下文无关语言由下推自动机识别。它们的工作方式与DFA类似,但需要添加堆栈。下推自动机使用输入的第一个字符和堆栈顶部的值选择转换。在每一步中,机器使用一个输入字符,可以在堆栈上推送一个值,弹出一个值,或者对堆栈不做任何操作

下推自动机可以使用堆栈来记住它们的位置,这使得它们适合于解析XML等语言(或大多数编程语言,只有少数例外)

解析XML

解析器不是通过设计下推自动机来构建的,就像你不能通过设计DFA来识别常规语言一样。上下文无关语法是描述上下文无关语言的更好方法。它们通常是以巴克斯·诺尔的形式(BNF)记录下来的。下面是XML子集的简单BNF语法:

Tags ::= Tag Tags | <nothing>

Tag ::= "<" /[a-zA-Z]+/ Attributes ">" Document "</" /[a-zA-Z]+/ ">"

Attributes ::= Attribute Attributes | <nothing>

Attribute ::= /[a-zA-Z]+/ "=" "\"" /[a-zA-Z0-9 ]+/ "\""
标签::=标签标签|
标记::=“”文档“”
属性::=属性属性|
属性::=/[a-zA-Z]+/“=”“\”“/[a-zA-Z0-9]+/”\“”
该语法由非终结符(“标记”、“标记”、“属性”和“属性”)组成。任何非终结符显示在规则右侧的地方,都可以用任何可能的定义(用|分隔)替换它。引号和正则表达式中的文本是终端,必须与输入完全匹配

标记非端子识别开始标记和结束标记,在它们之间有一个标记非端子。每当解析器识别开始标记时,它都希望在另一侧找到结束标记。标签将识别一个标签,然后再次识别标签。这种递归定义允许解析器识别无限数量的标记

解析器生成器是将上下文无关语法转换为下推自动机以识别输入语言的工具。这就降低了构建解析器的复杂性,尽管在准确指定语法方面有很多挑战

其他解析方法


您可以编写解析器,而无需手动构建状态机,也无需编写上下文无关语法。通常,这可以通过递归下降解析器或手工制作的解析器来完成,该解析器使用正则表达式,并具有有关所解析语言的一些特殊知识。递归下降解析器看起来很像上下文无关语法,但有一些严重的性能问题和功能限制。还有解析表达式语法(PEG),其工作原理类似于正则表达式和BNF语法的混合。Wikipedia上有关于所有这些技术的优秀文章,还有许多用于构建各种解析器的工具。

请继续阅读;通常,您一次遍历一个字符串的字符,跟踪要查找的内容,例如。“如果我看到一个
,那么它就是一个文本解析,类似于正则表达式引擎的工作方式——只专门针对预期的代码结构,以灵活性换取性能?类似,是的。事实上,在某些语言中很容易理解。不同之处在于,单个正则表达式不能很好地解释状态(例如,在
中搜索
/]+>/
),而解析器可以跟踪它的位置。我想不出还有什么我想知道的。非常感谢你的精彩回答!