Regex 为什么';使用正则表达式解析HTML/XML是不可能的:外行的正式解释';s条款
没有哪一天,人们会问到关于使用正则表达式解析(X)HTML或XML的问题 虽然提出或提出一个概念相对容易,但我仍然找不到一个如此正式的解释来解释为什么用外行的话来说这是不可能的 到目前为止,我在这个网站上所能找到的唯一正式解释可能非常准确,但对于自学成才的程序员来说,也是相当神秘的: 这里的缺陷是HTML是Chomsky类型2语法(上下文无关) RegEx是Chomsky类型3语法(正则表达式) 或: 正则表达式只能与正则语言匹配,但HTML是一种 上下文无关语言 或: 一个有限自动机(它是一个正则表达式的数据结构) 表达式)除了它所处的状态之外没有内存,如果 你有任意深的嵌套,你需要一个任意大的 自动机,它与有限自动机的概念相冲突 或: 正则语言的泵引理是您不能这样做的原因 那个 [公平地说:以上大部分解释都链接到维基百科页面,但这些页面并不比答案本身更容易理解] 因此,我的问题是:有没有人能用外行的话翻译一下上面给出的正式解释,解释为什么不能使用正则表达式解析(X)HTML/XML?Regex 为什么';使用正则表达式解析HTML/XML是不可能的:外行的正式解释';s条款,regex,language-agnostic,xpath,shell,python,perl,ruby,nokogiri,php,Regex,Language Agnostic,Xpath,Shell,Python,Perl,Ruby,Nokogiri,Php,没有哪一天,人们会问到关于使用正则表达式解析(X)HTML或XML的问题 虽然提出或提出一个概念相对容易,但我仍然找不到一个如此正式的解释来解释为什么用外行的话来说这是不可能的 到目前为止,我在这个网站上所能找到的唯一正式解释可能非常准确,但对于自学成才的程序员来说,也是相当神秘的: 这里的缺陷是HTML是Chomsky类型2语法(上下文无关) RegEx是Chomsky类型3语法(正则表达式) 或: 正则表达式只能与正则语言匹配,但HTML是一种 上下文无关语言 或: 一个有限自动机(它是一个
编辑:在阅读了第一个答案后,我想我应该澄清一下:我正在寻找一个“翻译”,它也简要地解释了它试图翻译的概念:在答案的结尾,读者应该有一个粗略的想法,例如,什么是“常规语言”和“上下文无关语法”意思是…,因为HTML可以有无限的
嵌套,而正则表达式不能真正处理这个问题,因为它不能跟踪它的起源和发展历史
一个简单的结构说明了困难:
<body><div id="foo">Hi there! <div id="bar">Bye!</div></div></body>
你好!再见!
99.9%的基于通用正则表达式的提取例程将无法正确地向我提供ID为
foo
的div
中的所有内容,因为它们无法区分该div的结束标记和bar
div的结束标记。这是因为它们无法说出“好的,我现在进入了两个div中的第二个,所以我看到的下一个div close将我带出一个,之后的一个是第一个div的close标签程序员通常通过为特定情况设计特殊的正则表达式来响应,然后在foo
中引入更多标记时,这些正则表达式就会中断,并且必须以巨大的时间和挫败感为代价取消编写。这就是为什么人们会对整件事感到愤怒。正则表达式是一台具有有限(通常相当小)离散状态数的机器
要使用任意嵌套的语言元素解析XML、C或任何其他语言,您需要记住自己的深度。也就是说,您必须能够计算大括号/括号/标记
你不能用有限的内存数数。支架级别可能比状态更多!您可能能够解析语言中限制嵌套级别数量的子集,但这将非常繁琐。语法是对单词位置的正式定义。例如,在英语语法中,形容词在名词
之前,但在名词之后。
上下文无关意味着语法在所有上下文中都通用。上下文敏感意味着在某些上下文中存在其他规则
例如,在C#中,使用
在使用系统中意味着不同的东西代码>位于文件顶部,而不是使用(var sw=new StringWriter(…)
。更相关的示例是代码中的以下代码:
void Start ()
{
string myCode = @"
void Start()
{
Console.WriteLine (""x"");
}
";
}
专注于这一点:
一个有限自动机(它是一个正则表达式的数据结构)
表达式)除了它所处的状态之外没有内存,如果
你有任意深的嵌套,你需要一个任意大的
自动机,它与有限自动机的概念相冲突
正则表达式的定义相当于一个事实,即字符串是否与模式匹配的测试可以由一个有限自动机(每个模式有一个不同的自动机)执行。一个有限自动机没有内存——没有堆栈,没有堆,没有无限的磁带可供涂鸦。它所拥有的只是有限数量的内部状态,每个状态都可以从被测试的字符串中读取一个单位的输入,并用它来决定下一个状态。作为特例,它有两种终止状态:“是的,匹配”和“否,不匹配”
另一方面,HTML具有可以嵌套任意深度的结构。要确定文件是否为有效的HTML,需要检查所有结束标记是否与以前的开始标记匹配。要理解它,您需要知道哪个元素正在关闭。如果没有任何方法“记住”你看到的开场白,就没有机会了
但是请注意,大多数“regex”库实际上允许的不仅仅是正则表达式的严格定义。如果它们能够匹配反向引用,那么它们已经超越了常规语言。因此,不应该在HTML上使用正则表达式库的原因比HTML不是正则表达式这一简单事实稍微复杂一些。正则表达式是一种可以被有限状态机匹配的语言
(理解有限状态机、下推机器和图灵机基本上是大学四年级CS课程的课程。)
考虑以下识别字符串“hi”的机器
这是一台识别规则l的简单机器
(Start) --Read h-->(A)--Read i-->(Succeed)
\ \
\ -- read any other value-->(Fail)
-- read any other value-->(Fail)
<!-- <h1>not the title!</h1> -->
<script>
var s = "Certainly <h1>not the title!</h1>";
</script>
<price>10.65</price>
(?:
<!\-\-[\S\s]*?\-\->
|
<([\w\-\.]+)[^>]*?
(?:
\/>
|
>
(?:
[^<]
|
(?R)
)*
<\/\1>
)
)