我看到人们一遍 又一遍地犯的一个错误是试图用正则表达式解析XML或HTML。 以下是难以解析XML和HTML的一些原因:

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

<tag
attr="5"
/>

人们希望将<或<tag视为标签的开头,但是类似的东西却普遍存在:

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

人们通常希望将开始标签与结束标签匹配,但是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>

您还知道其他哪些陷阱?


#1楼

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

也许正确的陈词滥调始于“当您只有锤子...”时,您知道如何使用正则表达式,正则表达式擅长解析,那么为什么还要花时间学习XML解析库呢?

因为解析XML很困难 。 您不必学习使用XML解析库而节省的任何工作,将远远超过您必须要做的创造性工作和减少错误的工作。 为了您自己的利益,谷歌“ XML库”并利用他人的工作。


#2楼

一般来说,由于XML语法绝非常规,因此无法使用正则表达式来解析XML。 简而言之,正则表达式无法计数(嗯,Perl正则表达式实际上可以计数),因此您无法平衡开闭标签。

我不同意。 如果要在正则表达式中使用递归,则可以轻松找到打开和关闭标签。

在这里,我展示了正则表达式的示例,以避免解析第一条消息中的示例错误。


#3楼

我认为问题可以归结为:

  1. 正则表达式几乎总是错误的。 存在合法输入,它将无法正确匹配。 如果您足够努力,则可以使它达到99%正确或99.999%的正确性,但是几乎不可能使它达到100%的正确性,这仅仅是由于XML使用实体允许的怪异事物。

  2. 如果正则表达式不正确,即使对于0.00001%的输入来说,则正则表达式也存在安全问题,因为有人会发现一个输入会破坏您的应用程序。

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

  4. 正则表达式很可能在中等大小的输入文件上表现很差。 我与XML的第一次接触是用一个正确的XML解析器替换一个(错误地)解析传入XML文档的Perl脚本,我们不仅将300行不可读的代码替换为任何人都可以理解的100行,而且还改善了用户响应时间从10秒到大约0.1秒。


#4楼

我在这里对这个问题给出了简化的答案。 虽然它不占100%的标记,但我解释了如果您愿意做一些预处理工作,那怎么可能。


#5楼

这取决于您“解析”的意思。 一般来说,由于XML语法绝非常规,因此无法使用正则表达式来解析XML。 简而言之,正则表达式无法计数(嗯,Perl正则表达式实际上可以计数),因此您无法平衡开闭标签。


#6楼

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

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

上一段带有一些警告。 现在,某些正则表达式实现支持递归的想法。 但是,一旦开始将递归添加到正则表达式中,您实际上就在扩展边界,应该考虑使用解析器。


#7楼

人们通常会默认编写贪婪模式,这通常会导致不加思索地通过。*将大块文件吞入尽可能大的<foo>。* </ foo>中。


#8楼

其实

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

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

这不是有效的XML,因为'<'和'>'在属性字符串中不是有效的字符。 需要使用相应的XML实体&lt; 和&gt;

它也不是有效的HTML,因为HTML中不允许使用短结束符(但在XML和XHTML中是正确的)。 根据HTML 4.01规范,“ img”标签也是隐式关闭的标签。 这意味着手动关闭它实际上是错误的,并且等同于关闭任何其他标签两次。

HTML的正确版本是

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

XHTML和XML的正确版本是

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

您提供的以下示例也无效

<
tag
attr="5"
/>

这也不是有效的HTML或XML。 标记的名称必须在'<'后面,尽管属性和结尾的'>'可能在他们想要的任何位置。 所以有效的XML实际上是

<tag
attr="5"
/>

这是另一个有趣的功能:您实际上可以选择使用“或”作为属性引号字符

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

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

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

基本上,XML不能使用正则表达式进行解析。 但是也没有理由这样做。 每种语言都有很多许多XML解析器。 您可以在SAX解析器,DOM解析器和Pull解析器之间进行选择。 所有这些保证都比使用正则表达式解析要快得多,然后您可以在结果DOM树上使用XPath或XSLT之类的出色技术。

因此,我的回答是:用正则表达式解析XML不仅很困难,而且也不是一个好主意。 只需使用数百万个现有XML解析器之一,即可利用XML的所有高级功能。

HTML太难了,甚至无法尝试自己解析。 首先,法律语法具有许多您可能不知道的细微之处,其次,狂野的HTML只是一大堆令人讨厌的东西(您不知所措)。 有各种各样的松散解析器库可以很好地处理诸如标记汤之类的HTML,只需使用它们即可。


#9楼

人们实际上是使用正则表达式犯了一个错误,还是仅仅足以胜任他们要完成的任务?

我完全同意,无法使用正则表达式解析html和xml,因为其他人已经回答了。

但是,如果您的要求不是解析html / xml,而是仅获取html / xml的“已知良好”位中的一小部分数据,那么正则表达式甚至是更简单的“子字符串”就足够了。


#10楼

这是一些有趣的有效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>&amp<br left><!---- >t<!---> < -->&e link </a>
</body>

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

祝您好运,正则表达式!

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

#11楼

不在列表中的一个陷阱是属性可以以任何顺序出现,因此,如果您的正则表达式正在查找带有href“ foo”和类“ bar”的链接,则它们可以以任何顺序出现,并且可以具有任意其他数量他们之间的事情。


#12楼

我相信这本 经典的书可以为您提供所需的信息。 您可以在其中的评论之一中找到要点:

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

来自Wikipedia的更多信息: Chomsky Hierarchy

您能否提供一些示例,说明为什么用正则表达式很难解析XML和HTML? [关闭]相关推荐

  1. 下载和安装MySQL官方提供的示例数据库(Employees)

    一.前言   在此之前笔者写过一篇博客<你说精通MySQL其实很菜jī(1):你不一定会的基本技巧或知识点(值得一看)>,本文内容是从那篇博客截取出来的.我们要学习MySQL相关的技术点, ...

  2. 应用笔记 UHD提供的示例 Ettus Research

    简介 本文将提供UHD代码示例UHD 是由Ettus Research研发的一款驱动器,能和所有的USRP™ 软件定义无线电兼容, UHD可在多个操作系统中(包括Linux, Windows and ...

  3. python解析xml文件elementtree_Python中使用ElementTree解析XML示例

    [XML基本概念介绍] XML 指可扩展标记语言(eXtensible Markup Language). XML 被设计用来传输和存储数据. 概念一: 复制代码 代码如下: # foo元素的起始标签 ...

  4. jdom解析xml文件_JDOM编辑XML文件示例

    jdom解析xml文件 JDOM provides very neat way to manipulate XML files, using JDOM is very easy and the cod ...

  5. 四种生成和解析XML文档的方法详解(介绍+优缺点比较+示例)

    众所周知,现在解析XML的方法越来越多,但主流的方法也就四种,即:DOM.SAX.JDOM和DOM4J 下面首先给出这四种方法的jar包下载地址 DOM:在现在的Java JDK里都自带了,在xml- ...

  6. php获得帮助类数据_PHP解析xml格式数据工具类示例

    本文实例讲述了PHP解析xml格式数据工具类.分享给大家供大家参考,具体如下: class ome_xml { /** * xml资源 * * @var resource * @see xml_par ...

  7. Qt解析XML及QTableWidget用法示例

    #include "widget.h" #include "ui_widget.h" #include <QFile> #include <Q ...

  8. java解析xml实例_在java中使用dom解析xml的示例分析

    本篇文章介绍了,在java中使用dom解析xml的示例分析.需要的朋友参考下 dom是个功能强大的解析工具,适用于小文档 为什么这么说呢?因为它会把整篇xml文档装载进内存中,形成一颗文档对象树 总之 ...

  9. java解析xml工具类_通过dom4j解析XML字符串XMLDocUtil工具类转换为XML文档及获取指定根节点及指定节点路径内容代码示例...

    一.前言 通过dom4j解析XML文档的XMLDocUtil工具类,进行解析xml字符串为Document文档对象.获取根节点元素路径内容getRootElement.获取唯一路径节点的值getSin ...

最新文章

  1. java 转换成时间戳_Java 实例 – 时间戳转换成时间 - Java 基础教程
  2. Mat转CImage
  3. 【论文解读】ICLR 2021丨当梯度提升遇到图神经网络,“鱼和熊掌”皆可兼得
  4. Java 异步编程:从 Future 到 Loom
  5. Android之解决NestedScrollView嵌套RecyclerView部分手机返回到这个页面Recyclerview顶部,而不是页面NestedScrollView顶部
  6. Android导入第三方静态库.a编译成动态库.so
  7. linux下安装yum步骤
  8. python图像灰度化、二值化
  9. 海森矩阵(Hessian)
  10. JavaWeb-HTML
  11. java冰箱评测开题报告范文_智能电冰箱控制的设计开题报告.doc
  12. [洛谷P3987]我永远喜欢珂朵莉~
  13. 【BUG】unresolvable R_ARM_THM_CALL relocation against symbol `strlen'
  14. 移动硬盘插入提示需要格式化RAW_移动硬盘数据恢复 – 图文教程
  15. uchome的安装记录
  16. 谷歌雅虎新闻大战-两种路线的PK
  17. android的数据存储(3)(LitePal)
  18. 单片机搭建环境烧录方法_万物互联-stm32单片机简介、烧录、编程及其项目环境搭建...
  19. Linux内存是怎么工作的?
  20. java连不上sqlserver_java和SQL连接不上——解决步骤

热门文章

  1. “大龄”码农的“中年危机”:35岁之后,该如何应对?
  2. android MotionEvent
  3. 算法:枚举法---kotlin
  4. PHP学习笔记-数组
  5. (0104)iOS开发之在Mac上用Charles给iPhone抓包
  6. Mac-使用文本编辑的html浏览器打开出现源代码问题
  7. 在java的实现栈的插入数据_Java实现数据结构栈stack和队列Queue
  8. (转)linux如何让历史记录不记录敏感命令
  9. Linux云自动化运维第十课
  10. 原型链Object的一些方法