你能提供一些为什么很难用正则expression式来parsingXML和HTML的例子吗?

我看到人们一遍又一遍的错误是试图用正则expression式来parsingXML或HTML。 以下是parsingXML和HTML的一些原因:

人们希望将文件视为一系列的行,但这是有效的:

<tag attr="5" /> 

人们希望将<或<标签作为标签的开头,但是像这样的东西存在于野外:

 <img src="imgtag.gif" alt="<img>" /> 

人们通常希望匹配起始标签到结束标签,但XML和HTML允许标签包含自己(传统的正则expression式根本无法处理):

 <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> 

你还知道什么其他的陷阱?

这里有一些有趣的有效XML:

 <!DOCTYPE x [ <!ENTITY y "a]>b"> ]> <x> <ab="&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> &amp<br left> <!---- >t<!---> < --> &e link </a> </body> 

更不用说所有针对无效构造的浏览器特定分析。

祝你好运正则expression式反对!

编辑(JörgW 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/> 

其实

 <img src="imgtag.gif" alt="<img>" /> 

不是有效的HTML,也不是有效的XML。

它不是有效的XML,因为“<”和“>”在属性string中不是有效的字符。 他们需要使用相应的XML实体&lt; 和&gt;

它不是有效的HTML,因为HTML中不允许使用简短的closures表单(但在XML和XHTML中是正确的)。 根据HTML 4.01规范,'img'标签也是一个隐式closures的标签。 这意味着手动closures它实际上是错误的,相当于closures任何其他标签两次。

HTML中的正确版本是

 <img src="imgtag.gif" alt="&lt;img&gt;"> 

而XHTML和XML中的正确版本是

 <img src="imgtag.gif" alt="&lt;img&gt;"/> 

你给的下面的例子也是无效的

 < tag attr="5" /> 

这不是有效的HTML或XML。 标签的名称必须在“<”后面,尽pipe属性和closures“>”可能在任何他们想要的地方。 所以有效的XML实际上是

 <tag attr="5" /> 

这里还有一个更好玩的:你可以select使用“或”作为你的属性引用字符

 <img src="image.gif" alt='This is single quoted AND valid!'> 

所有其他发布的原因都是正确的,但parsingHTML的最大问题是人们通常不能正确理解所有的语法规则。 事实上,您的浏览器将您的tagsoup解释为HTML并不意味着您实际上已经编写了有效的HTML。

编辑:甚至stackoverflow.com同意我关于有效和无效的定义。 您无效的XML / HTML不会突出显示,而我的更正版本是。

基本上,XML不会被正则expression式parsing。 但是也没有理由这样做。 每种语言都有很多很多的XMLparsing器。 您可以在SAXparsing器,DOMparsing器和Pullparsing器之间进行select。 所有这些保证比使用正则expression式parsing要快得多,然后您可以在生成的DOM树上使用像XPath或XSLT这样的酷技术。

因此,我的回答是:不仅用正则expression式parsingXML,而且也是一个坏主意。 只需使用数百万现有的XMLparsing器之一,并利用XML的所有高级function。

HTML太难以甚至尝试parsing你自己的。 首先,法律语法有许多你可能没有意识到的微妙之处,其次,HTML中的狂野只是一大堆(你让我的漂移)。 有许多松散的parsing器库,在处理标签汤这样的HTML方面做得很好,只需要使用这些库。

我写了关于这个主题的整个博客条目: 正则expression式的限制

问题的症结在于,HTML和XML是recursion结构,需要计数机制才能正确parsing。 一个真正的正则expression式不能算数。 你必须有一个上下文无关的语法来计数。

上一段有一个小小的警告。 某些正则expression式实现现在支持recursion的思想。 然而,一旦你开始在你的regexexpression式中添加recursion,你真的在​​扩展边界,应该考虑一个parsing器。

一个不在列表中的是属性可以以任何顺序出现,所以如果你的正则expression式正在寻找一个带有href“foo”和类“bar”的链接,它们可以以任何顺序出现,他们之间的事情。

这取决于你的意思是“parsing”。 一般来说,不能使用正则expression式来分析XML,因为XML语法决不是常规的。 简单地说,正则expression式不能计数(当然,Perl正则expression式实际上可以计算事物),所以你不能平衡开闭标签。

人们使用正则expression式实际上是犯了一个错误,还是仅仅是他们试图实现的任务?

我完全同意,parsingHTML和XML使用正则expression式是不可能的,因为其他人已经回答。

但是,如果您的要求不是parsinghtml / xml,而只是在html / xml的“已知好”位获取一小部分数据,则可能是正则expression式,甚至更简单的“子string”就足够了。

人们通常会默认编写贪婪的模式,经常会导致一个没有经过深思熟虑的过程。*将大块文件拖入最大可能的<foo>。* </ foo>中。

我很想说“不要重新发明轮子”。 除了XML是一个非常复杂的格式。 所以也许我应该说“不要重新发明同步加速器”。

也许正确的陈词滥调开始“当你所有的是锤子…”你知道如何使用正则expression式,正则expression式擅长parsing,所以为什么要学习一个XMLparsing库?

因为parsingXML很困难 。 无需学习使用XMLparsing库,您所节省的任何努力将不仅仅是由创造性工作量和错误捕获量来弥补。 为了你自己,谷歌“XML库”,并利用别人的工作。

我相信这个 经典有您正在寻找的信息。 您可以在其中的一条评论中find这一点:

我认为这里的缺点是,HTML是乔姆斯基2型语法(上下文无关语法),正则expression式是乔姆斯基3型语法(正则expression式)。 由于第二类语法比第三类语法复杂得多,所以你不可能希望这样做 。 但许多人会尝试,有些人会声称成功,其他人会发现错误,并把你搞砸。

来自Wikipedia的更多信息: Chomsky Hierarchy

我认为问题归结为:

  1. 正则expression式几乎总是不正确的。 有合法的投入,它将无法正确匹配。 如果你努力工作的话,你可以使99%正确,或者99.999%,但是如果仅仅因为XML允许使用实体的奇怪事情而使得100%正确,那么几乎是不可能的。

  2. 如果正则expression式不正确,即使对于0.00001%的input,那么你也有一个安全问题,因为有人可以发现一个input会打破你的应用程序。

  3. 如果正则expression式足够覆盖99.99%的情况,那么这将是彻头彻尾的不可读和不可维护的。

  4. 正则expression式很可能在中等大小的input文件上执行得非常糟糕。 我第一次遇到XML是用一个正确的XMLparsing器来replace一个Perl脚本(错误地)parsing传入的XML文档,并且我们不仅用任何人都可以理解的100行代替了300行不可读的代码,但是我们改进了用户响应时间从10秒到约0.1秒。

一般来说,不能使用正则expression式来分析XML,因为XML语法决不是常规的。 简单地说,正则expression式不能计数(当然,Perl正则expression式实际上可以计算事物),所以你不能平衡开闭标签。

我不同意。 如果您将在regex中使用recursion,您可以轻松find打开和closures标记。

这里我展示了正则expression式的例子,以避免parsing第一条消息中的例子的错误。

我在这里给了这个问题一个简单的答案。 虽然它没有达到100%的标准,但我解释了如果你愿意做一些预处理工作,这是可能的。