您能否提供一些示例说明为啥使用正则表达式难以解析 XML 和 HTML? [关闭]
Posted
技术标签:
【中文标题】您能否提供一些示例说明为啥使用正则表达式难以解析 XML 和 HTML? [关闭]【英文标题】:Can you provide some examples of why it is hard to parse XML and HTML with a regex? [closed]您能否提供一些示例说明为什么使用正则表达式难以解析 XML 和 HTML? [关闭] 【发布时间】:2010-10-16 14:45:54 【问题描述】:我看到人们犯over 和over again 的一个错误是尝试使用正则表达式解析XML 或html。以下是解析 XML 和 HTML 困难的几个原因:
人们希望将文件视为一系列行,但这是有效的:
<tag
attr="5"
/>
人们希望将
<img src="imgtag.gif" />
人们通常希望将开始标签与结束标签匹配,但 XML 和 HTML 允许标签包含自己(传统的正则表达式根本无法处理):
<span id="outer"><span id="inner">foo</span></span>
人们经常希望匹配文档的内容(例如著名的“查找给定页面上的所有电话号码”问题),但数据可能会被标记(即使在查看时看起来很正常) :
<span class="phonenum">(<span class="area code">703</span>)
<span class="prefix">348</span>-<span class="linenum">3020</span></span>
评论可能包含格式错误或不完整的标签:
<a href="foo">foo</a>
<!-- FIXME:
<a href="
-->
<a href="bar">bar</a>
您还知道哪些其他问题?
【问题讨论】:
网络浏览器每秒能理解这种混乱数百万次,难道不能有人为我们这些凡人创建一个网页解析器类吗? 乔恩,他们有。在 Perl 中有许多 HTML::Parser、HTML::TreeBuilder 等。几乎可以肯定有一个适合您的语言。 Jon,您在寻找什么语言,您是否在寻找解析格式良好的 XML 或您在网络上获得的 HTML 标签汤? 最好的答案是,***.com/a/1732454/135078(当心 Zalgo) 这是a good explanation of how you certainly can parse HTML with patterns,以及您可能不希望这样做的原因。 【参考方案1】:这里有一些有趣的有效 XML 供您参考:
<!DOCTYPE x [ <!ENTITY y "a]>b"> ]>
<x>
<a b="&y;>" />
<![CDATA[[a>b <a>b <a]]>
<?x <a> <!-- <b> ?> c --> d
</x>
这个小小的快乐是有效的 HTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" [
<!ENTITY % e "href='hello'">
<!ENTITY e "<a %e;>">
]>
<title>x</TITLE>
</head>
<p id = a:b center>
<span / hello </span>
&<br left>
<!---- >t<!---> < -->
&e link </a>
</body>
更不用说所有针对无效结构的特定于浏览器的解析。
祝你好运与正则表达式对抗!
编辑(Jörg W Mittag):这是另一个很好的格式良好、有效的 HTML 4.01:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<HTML/
<HEAD/
<TITLE/>/
<P/>
【讨论】:
XML 那个?那里有几种不同的构造,哪个很麻烦? DTD 内部子集?那就是定义一个新的 &entity;称为“y”,包含一个“]>”序列,如果不在引号中,通常会结束内部子集。 (这表明您必须对 XML 的一些更深奥和古老的 DTD 特性有相当深入的了解才能正确解析文档,即使您不是 DTD 验证解析器。) HTML 示例使用了一个鲜为人知的特性:短标签。阅读更多w3.org/QA/2007/10/shorttags.html 每当有人编写如上图所示的 HTML 时,Tim Berners-Lee 都会流泪。 我喜欢 *** 的语法荧光笔在第一次出现“]”时失败的方式。【参考方案2】:其实
<img src="imgtag.gif" />
不是有效的 HTML,也不是有效的 XML。
它不是有效的 XML,因为 '' 不是属性字符串中的有效字符。它们需要使用相应的 XML 实体 < 进行转义。和>
它也不是有效的 HTML,因为 HTML 中不允许使用短结束形式(但在 XML 和 XHTML 中是正确的)。根据 HTML 4.01 规范,“img”标签也是一个隐式封闭标签。这意味着手动关闭它实际上是错误的,相当于关闭任何其他标签两次。
HTML 中正确的版本是
<img src="imgtag.gif" >
XHTML 和 XML 中的正确版本是
<img src="imgtag.gif" />
下面你给出的例子也是无效的
<
tag
attr="5"
/>
这也不是有效的 HTML 或 XML。标签的名称必须紧跟在“”可能在他们想要的任何位置。所以有效的 XML 实际上是
<tag
attr="5"
/>
还有一个更有趣的:您实际上可以选择使用 " 或 ' 作为属性引用字符
<img src="image.gif" alt='This is single quoted AND valid!'>
发布的所有其他原因都是正确的,但解析 HTML 的最大问题是人们通常无法正确理解所有语法规则。您的浏览器将您的 tagoup 解释为 HTML 的事实并不意味着您实际上编写了有效的 HTML。
编辑:甚至 ***.com 都同意我关于有效和无效的定义。您的无效 XML/HTML 没有突出显示,而我的更正版本是。
基本上,XML 不是用正则表达式解析的。但也没有理由这样做。每种语言都有很多很多 XML 解析器。您可以在 SAX 解析器、DOM 解析器和 Pull 解析器之间进行选择。所有这些都保证比使用正则表达式解析要快得多,然后您可以在生成的 DOM 树上使用 XPath 或 XSLT 等很酷的技术。
因此,我的回答是:不仅用正则表达式解析 XML 很困难,而且也是一个坏主意。只需使用数以百万计的现有 XML 解析器之一,并利用 XML 的所有高级特性。
HTML 太难了,甚至无法自己尝试解析。首先,法律语法有许多您可能不知道的细微之处,其次,野外的 HTML 只是一大堆臭气熏天的东西(你明白我的意思)。有各种松散的解析器库可以很好地处理 HTML,如标签汤,只需使用这些。
【讨论】:
你不需要像 > 一样逃跑。 好的,s/valid/野外存在/g 其实按照规范你必须转义 > as > 就像你必须转义 规范中没有说‘>’必须转义 — 内容中序列‘]]>’的特殊情况除外。出于这个原因,总是转义“>”是最容易的,但规范并不要求它。>
符号在 html 中完全有效 ***.com/questions/94528/…【参考方案3】:
我写了一篇关于这个主题的完整博客文章:Regular Expression Limitations
问题的症结在于 HTML 和 XML 是递归结构,需要计数机制才能正确解析。真正的正则表达式无法计数。你必须有上下文无关的语法才能计算。
上一段带有一点警告。某些正则表达式实现现在支持递归的想法。但是,一旦您开始将递归添加到您的正则表达式中,您实际上是在扩展界限,应该考虑使用解析器。
【讨论】:
【参考方案4】:您的列表中没有的一个问题是属性可以以任何顺序出现,因此如果您的正则表达式正在寻找带有 href "foo" 和类 "bar" 的链接,它们可以以任何顺序出现,并且有任何它们之间的其他事物的数量。
【讨论】:
啊,是的,这甚至是促使我问这个的问题(第一个链接)。【参考方案5】:这取决于您所说的“解析”是什么意思。一般来说,XML 不能使用正则表达式解析,因为 XML 语法绝不是规则的。简而言之,正则表达式无法计数(好吧,Perl 正则表达式实际上可能能够计数),因此您无法平衡打开-关闭标签。
【讨论】:
我猜反向引用可以解决打开和关闭标签的问题 @RishulMatta:怎么样?您只有有限数量的反向引用,请注意您需要反转标签......此外,正则表达式的严格定义不允许反向引用。 .NET 允许平衡表达式,弹出和推送,理论上可以用于匹配层次结构。但这仍然是个坏主意。【参考方案6】:人们是否真的在使用正则表达式时犯了错误,或者它对于他们想要完成的任务是否足够好?
我完全同意使用正则表达式解析 html 和 xml 是不可能的,因为其他人已经回答了。
但是,如果您的要求不是解析 html/xml,而只是在“已知良好”的 html/xml 位中获取一小部分数据,那么可能是正则表达式甚至更简单的“子字符串”足够好。
【讨论】:
定义“足够好”。不可避免地,简单的正则表达式将不起作用。不匹配的东西或匹配的东西你不应该是一个错误?如果是这样,那么使用正则表达式是一个错误。 HTML 和 XML 解析器并不难使用。避免学习它们是一种虚假的经济。 好的,定义“足够好”。假设我有一个网页可以告诉我客户端的 IP 地址。这就是它所做的一切。现在,我需要为客户端机器编写一个应用程序,告诉我它的 IP 地址。我去那个网站,寻找一个IP地址并返回它。不需要解析 HTML! 如果您有一个格式完全受您控制的任意字符串,那么该字符串恰好是格式良好的 XML 的事实实际上并不相关。但实际上几乎没有 XML 用例属于这一类。 我可以从痛苦的经历告诉你,大多数时候使用荒谬的复杂正则表达式模式可以获得你想要的东西。直到网站发生了一个有趣的小改动,你可以把这个让你哭了两天的正则表达式扔到窗外重新开始。 @Robert:“几乎没有用例”是夸大其词。以我的经验,有足够常见的用例。 YAGNI 适用于此……有时。诀窍是知道您的解决方案对于您正在处理的特定任务需要多么防弹和长寿。罗宾有一个很好的观点。他只是说完整的 XML 解析并不总是值得的......即使你知道如何使用它也是如此。【参考方案7】:我很想说“不要重新发明***”。除了 XML 是一种非常、非常复杂的格式。所以也许我应该说“不要重新发明同步加速器。”
也许正确的陈词滥调开始“当你只有一把锤子......”你知道如何使用正则表达式,正则表达式擅长解析,那么为什么还要学习XML解析库呢?
因为解析 XML 是困难。您不必学习使用 XML 解析库而节省的任何努力都将远远超过您必须做的创造性工作量和 bug 扑灭量。为了你自己,谷歌“XML 库”并利用其他人的工作。
【讨论】:
虽然没有 C++ 复杂。 @Cole"Cole9"Johnson 我也不会使用 RE 来解析 C++。 如果 XML 是同步加速器,C++ 就是大型强子对撞机。【参考方案8】:人们通常默认编写贪婪模式,这通常会导致未经深思熟虑的 .* 将大块文件吞入尽可能大的
【讨论】:
除了用.*?<
使重复变得懒惰之外,您还可以通过使用像[^<]*<
这样的否定字符类来解决这个问题。 (免责声明:显然这仍然不是万无一失的,这是问题的重点。)【参考方案9】:
我认为问题归结为:
正则表达式几乎总是不正确的。存在无法正确匹配的合法输入。如果你足够努力,你可以让它 99% 正确,或者 99.999%,但是让它 100% 正确几乎是不可能的,如果仅仅是因为 XML 允许使用实体来实现一些奇怪的事情。
如果正则表达式不正确,即使是 0.00001% 的输入,也存在安全问题,因为有人会发现会破坏您的应用程序的输入。
如果正则表达式正确到足以涵盖 99.99% 的情况,那么它将完全不可读和不可维护。
正则表达式很可能在中等大小的输入文件上表现不佳。我第一次接触 XML 是用适当的 XML 解析器替换一个(错误地)解析传入 XML 文档的 Perl 脚本,我们不仅用 100 行任何人都可以理解的代码替换了 300 行不可读的代码,而且我们改进了用户响应时间从 10 秒到大约 0.1 秒。
【讨论】:
【参考方案10】:我相信this classic 有您正在寻找的信息。您可以在其中一个 cmets 中找到要点:
我认为这里的缺陷是 HTML 是 Chomsky Type 2 语法 (上下文无关语法)和 RegEx 是 Chomsky Type 3 语法(正则 表达)。 因为第 2 类语法基本上比 第 3 类语法 - 你不可能希望完成这项工作。但是很多 会尝试,有些人会声称成功,有些人会发现错误并 完全把你搞砸了。
来自***的更多信息:Chomsky Hierarchy
【讨论】:
“正则表达式”在正式语法讨论中的含义与此处不同。大多数现存的正则表达式引擎比 Chomsky Type 3 语法更强大(例如非贪婪匹配、反向引用)。一些正则表达式引擎(例如 Perl 的)是图灵完备的。确实,即使是那些解析 HTML 的工具也很糟糕,但这个经常被引用的论点并不是原因。【参考方案11】:我对这个问题给出了一个简化的答案here。虽然它不占 100% 的标记,但我解释了如果您愿意做一些预处理工作是如何实现的。
【讨论】:
【参考方案12】:一般来说,XML 不能使用正则表达式来解析,因为 XML 语法绝不是规则的。简而言之,正则表达式无法计数(好吧,Perl 正则表达式实际上可能能够计数),因此您无法平衡打开-关闭标签。
我不同意。如果您将在正则表达式中使用递归,您可以轻松找到打开和关闭标签。
Here我展示了正则表达式的示例,以避免在第一条消息中解析示例的错误。
【讨论】:
首先,递归正则表达式不是正则表达式(如果你看括号,你会发现我承认 Perl 的正则表达式是递归的,可以计算事物,这是处理 HTML 所必需的) .其次,您的示例适用于格式良好的 XHTML 或 XML。 HTML 格式不正确。第三,你必须问自己,用递归正则表达式语言或通用编程语言编写的解析器更容易扩展和维护。 第四,即使您的示例在仍然是有效的 XML 时也被简单地破坏了。在 content_block 和 id 之间加一个空格会失败。我敢肯定,如果我再花几分钟,我会在您的代码中发现一些其他结构错误。这不是一个好主意。以上是关于您能否提供一些示例说明为啥使用正则表达式难以解析 XML 和 HTML? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章