您能否举例说明为什么用正则表达式解析XML和HTML很困难?

Cha*_*ens 397 html regex xml

一个错误我看到人们做,并再次试图解析XML或HTML用正则表达式.以下是解析XML和HTML很难的几个原因:

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

<tag
attr="5"
/>
Run Code Online (Sandbox Code Playgroud)

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

<img src="imgtag.gif" alt="<img>" />
Run Code Online (Sandbox Code Playgroud)

人们通常希望将起始标记与结束标记匹配,但XML和HTML允许标记包含自身(传统的正则表达式根本无法处理):

<span id="outer"><span id="inner">foo</span></span> 
Run Code Online (Sandbox Code Playgroud)

人们通常希望匹配文档的内容(例如着名的"查找给定页面上的所有电话号码"问题),但数据可能会被标记(即使在查看时看起来是正常的):

<span class="phonenum">(<span class="area code">703</span>)
<span class="prefix">348</span>-<span class="linenum">3020</span></span>
Run Code Online (Sandbox Code Playgroud)

评论可能包含格式不正确或不完整的标记:

<a href="foo">foo</a>
<!-- FIXME:
    <a href="
-->
<a href="bar">bar</a>
Run Code Online (Sandbox Code Playgroud)

你还知道其他什么问题?

bob*_*nce 259

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

<!DOCTYPE x [ <!ENTITY y "a]>b"> ]>
<x>
    <a b="&y;>" />
    <![CDATA[[a>b <a>b <a]]>
    <?x <a> <!-- <b> ?> c --> d
</x>
Run Code Online (Sandbox Code Playgroud)

而这一小小的快乐是有效的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>
Run Code Online (Sandbox Code Playgroud)

更不用说针对无效结构的所有特定于浏览器的解析.

好运pitting正则表达式反对!

编辑(JörgWMittag):这是另一个结构良好,有效的HTML 4.01:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
  "http://www.w3.org/TR/html4/strict.dtd"> 
<HTML/
  <HEAD/
    <TITLE/>/
    <P/>
Run Code Online (Sandbox Code Playgroud)

  • 每当有人写下如上所示的HTML时,Tim Berners-Lee就会流下眼泪. (24认同)
  • HTML示例使用了一个鲜为人知的功能:shorttags.更多信息,请访问http://www.w3.org/QA/2007/10/shorttags.html (17认同)
  • (这表明您必须非常深入地了解XML的一些更深奥和古老的DTD功能才能正确解析文档,即使您不是DTD验证解析器.) (16认同)
  • XML一个?那里有一些不同的结构,这很麻烦?DTD内部子集?这是一个新的实体; 称为'y',包含']>'序列,如果不是引号,通常会结束内部子集. (6认同)
  • 我喜欢Stackoverflow的语法荧光笔在第一次出现"]时失败了. (5认同)
  • @GlassGhost因为Prettifyer基于正则表达式:P所以是GeSHi (3认同)
  • @dorukayhan:HTML4正式基于SGML(即使浏览器没有解析它).SGML的规则主要是疯子.那些未公开的元素实际上是[NETs](https://en.wikipedia.org/wiki/Standard_Generalized_Markup_Language#NET) (3认同)

Lor*_*igs 70

其实

<img src="imgtag.gif" alt="<img>" />
Run Code Online (Sandbox Code Playgroud)

是无效的HTML,也不是有效的XML.

它不是有效的XML,因为'<'和'>'在属性字符串中不是有效字符.它们需要使用相应的XML实体进行转义< 和>

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

HTML中的正确版本是

<img src="imgtag.gif" alt="&lt;img&gt;">
Run Code Online (Sandbox Code Playgroud)

XHTML和XML中的正确版本是

<img src="imgtag.gif" alt="&lt;img&gt;"/>
Run Code Online (Sandbox Code Playgroud)

您提供的以下示例也无效

<
tag
attr="5"
/>
Run Code Online (Sandbox Code Playgroud)

这也不是有效的HTML或XML.标签的名称必须位于"<"后面,尽管属性和结束">"可能位于他们想要的任何位置.所以有效的XML实际上就是这样

<tag
attr="5"
/>
Run Code Online (Sandbox Code Playgroud)

这是另一个更有趣的一个:你实际上可以选择使用"或"作为你的属性引用字符

<img src="image.gif" alt='This is single quoted AND valid!'>
Run Code Online (Sandbox Code Playgroud)

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

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

基本上,XML不能用regexp解析.但也没有理由这样做.每种语言都有许多XML解析器.您可以选择SAX解析器,DOM解析器和Pull解析器.所有这些都保证比使用正则表达式解析要快得多,然后您可以在生成的DOM树上使用XPath或XSLT等酷技术.

因此,我的回答是:不仅难以用正则表达式解析XML,而且这也是一个坏主意.只需使用数百万个现有XML解析器中的一个,并利用XML的所有高级功能.

HTML甚至难以自己解析.首先,法律语法有许多你可能不知道的微妙之处,其次,野外的HTML只是一堆巨大的(你得到我的漂移).有很多松散的解析器库可以很好地处理像标签汤这样的HTML,只需使用它们.

  • 规范并未说'>'必须转义 - 除了内容中序列']]>'的特殊情况.因此,最容易总是逃避'>',但规范并不要求它. (19认同)
  • 你不需要逃避> as>. (8认同)
  • 好的,s/valid /存在于wild/g中 (8认同)
  • `>`符号在html中完全有效http://stackoverflow.com/questions/94528/is-u003e-greater-than-sign-allowed-inside-an-html-element-attribute-value (8认同)

Jar*_*Par 56

我写了一篇关于这个主题的完整博客文章:正则表达式限制

问题的关键在于HTML和XML是递归结构,需要计数机制才能正确解析.真正的正则表达式无法计数.您必须具有无上下文语法才能计算.

前一段有一点需要注意.某些正则表达式实现现在支持递归的想法.但是,一旦开始将recursion添加到正则表达式中,您实际上是在扩展边界并且应该考虑使用解析器.


Amb*_*pel 20

你的列表中没有一个问题是属性可以按任何顺序出现,所以如果你的正则表达式正在寻找带有href"foo"和类"bar"的链接,它们可以按任何顺序排列,并且有任意数量的其他他们之间的事情.


Ant*_*lev 16

这取决于"解析"的含义.一般来说,XML无法使用正则表达式进行解析,因为XML语法绝不是常规的.简而言之,正则表达式无法计算(好吧,Perl正则表达式实际上可以计算事物),因此您无法平衡开闭标签.


Rob*_*Day 9

人们实际上是通过使用正则表达式犯了错误,还是仅仅对他们想要实现的任务足够好?

我完全同意使用正则表达式解析html和xml是不可能的,因为其他人已经回答了.

但是,如果你的要求不是解析html/xml,而只是在html/xml的"已知良好"位中得到一小部分数据,那么正则表达式甚至更简单的"子串"就足够了.

  • 我可以从痛苦的经历中告诉你,大部分时间都可以利用荒谬的复杂正则表达式来获得你想要的东西.直到网站经历了一个热闹的小变化,你可以抛出这个让你在窗外哭了两天然后重新开始的正则表达式. (15认同)
  • 定义"足够好".简单的正则表达式不可避免地会起作用.是不匹配的东西或匹配的东西,你不应该是一个错误?如果是这样,那么使用正则表达式是一个错误.HTML和XML解析器并不难使用.避免学习它们是一种虚假的经济. (7认同)
  • 如果你有一个任意字符串,其格式完全在你的控制之下,那么字符串碰巧是格式良好的XML的事实确实是不相关的.但几乎没有XML用例实际上属于这一类. (2认同)

cha*_*aos 6

人们通常默认编写贪婪的模式,通常足以导致无法思考.*将大块文件啜饮到最大可能的<foo>.*</ foo>.

  • 除了使用`.*?<`进行重复延迟之外,你可以通过使用像`[^ <]*<`这样的否定字符类来解决这个问题.(免责声明:显然,这仍然不是万无一失的,这就是问题的关键所在.) (2认同)

Isa*_*tch 6

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

也许正确的陈词滥调开始"当你拥有的只是一把锤子......"你知道如何使用正则表达式,正则表达式擅长解析,那么为什么还要学习XML解析库呢?

因为解析XML 很难.通过不必学习使用XML解析库而节省的任何努力将超过您必须做的创造性工作量和错误捕获量.为了您自己,谷歌"XML库",并利用其他人的工作.

  • @Cole"Cole9"Johnson我也不会使用RE来解析C++. (6认同)
  • 它并不像C++那么复杂. (3认同)
  • 如果XML是同步加速器,C++将是大型强子对撞机. (2认同)

Ada*_*old 5

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

我认为这里的缺陷是 HTML 是 Chomsky Type 2 语法(上下文无关语法),而 RegEx 是 Chomsky Type 3 语法(正则表达式)。由于类型 2 语法从根本上比类型 3 语法更复杂 - 您不可能希望使这项工作成功。但是很多人会尝试,有些人会声称成功,而另一些人会发现错误并完全把你搞砸。

来自维基百科的更多信息:乔姆斯基层次结构

  • “正则表达式”在正式语法讨论中与此处的含义并不完全相同。大多数现存的正则表达式引擎都比 Chomsky Type 3 语法更强大(例如非贪婪匹配、反向引用)。一些正则表达式引擎(例如 Perl 的)是图灵完备的。确实,即使是那些用于解析 HTML 的工具也很糟糕,但是这个经常被引用的论点并不是原因所在。 (6认同)

Mic*_*Kay 5

我认为问题归结为:

  1. 正则表达式几乎总是不正确的。存在无法正确匹配的合法输入。如果你足够努力,你可以使它 99% 或 99.999% 正确,但是使它 100% 正确几乎是不可能的,因为 XML 允许使用实体进行一些奇怪的事情。

  2. 如果正则表达式不正确,即使是 0.00001% 的输入,那么您就会遇到安全问题,因为有人可以发现会破坏您的应用程序的一个输入。

  3. 如果正则表达式足够正确以涵盖 99.99% 的情况,那么它将完全不可读和不可维护。

  4. 正则表达式很可能在中等大小的输入文件上表现非常糟糕。我第一次遇到 XML 是用适当的 XML 解析器替换(错误地)解析传入 XML 文档的 Perl 脚本,我们不仅用 100 行任何人都能理解的代码替换了 300 行不可读的代码,而且我们改进了用户响应时间从 10 秒到大约 0.1 秒。