题 除了XHTML自包含标记之外,RegEx匹配开放标记


我需要匹配所有这些开始标记:

<p>
<a href="foo">

但不是这些:

<br />
<hr class="foo" />

我想出了这个,并希望确保我做对了。我只抓住了 a-z

<([a-z]+) *[^/]*?>

我相信它说:

  • 找一个小于,然后
  • 然后,找到(并捕获)a-z一次或多次
  • 找到零个或多个空格,然后
  • 查找任何字符零次或多次,贪心,除外 /, 然后
  • 找到一个大于

我有这个权利吗?更重要的是,你怎么看?


1324
2017-09-27 04:01


起源




答案:


您无法使用正则表达式解析[X] HTML。因为正则表达式无法解析HTML。正则表达式不是可用于正确解析HTML的工具。正如我之前在HTML-and-regex问题中回答过很多次,使用正则表达式不允许您使用HTML。正则表达式是一种不太复杂的工具,无法理解HTML所使用的构造。 HTML不是常规语言,因此无法通过正则表达式进行解析。正则表达式查询不能将HTML分解为有意义的部分。这么多次,但它没有找到我。即使是Perl使用的增强的不规则正则表达式也不能完成解析HTML的任务。你永远不会让我破解。 HTML是一种足够复杂的语言,无法通过正则表达式进行解析。甚至Jon Skeet也无法使用正则表达式解析HTML。每当你试图用正则表达式解析HTML时,邪恶的孩子就会为处女的鲜血哭泣,而俄罗斯黑客则会把你的webapp用来。用正则表达式解析HTML会将受污染的灵魂召唤到生活的领域。 HTML和正则表达式像爱情,婚姻和仪式杀婴一样。 <center>无法忍受为时已晚。正则表达式和HTML一起在同一个概念空间中的力量会像肮脏的腻子一样摧毁你的思想。如果你用正则表达式解析HTML,你就会屈服于他们和他们的亵渎神灵的方式,这些方式让我们所有人都无法为那些名字无法在基本多语言平面中表达的人付出辛苦劳苦,他来了。当你观察时,HTML-plus-regexp将会使有感情的人群流动,你的心灵在恐怖的冲击中萎缩。基于Rege̿̔̉x的HTML解析器是杀死StackOverflow的癌症 现在为时已晚,我们无法得救 一个chi͡ld的传统确保正则表达式将消耗所有活组织(除了HTML,它不能,如先前预言的那样) 亲爱的领主帮助我们如何在这个祸害中幸存下来 使用正则表达式解析HTML已经注定了人类永远的恐惧折磨和安全漏洞 使用regex作为处理HTML的工具建立了一个brea在这个世界之间 和破坏实体的恐惧领域(如SGML实体,但是 更腐败)只是一瞥reg的世界ex解析器将用于HTMLt t t t trogrammer的意识我nto a wORLd不停尖叫,他来了,pestilent slithy regex-infection wil我吞噬你的HTML解析器,应用程序和存在像Visual Basic一样只会更糟 他来了他ES 不要ecom̡e̶s,̕h̵isun̨ho͞lyradiańcédestro҉ying所有enli̍̈̈ghtenment,HTML标签 lea͠ki̧n͘gfr̶ǫm̡yo͟ureye͢s̸̸l̕ik͏eliquid pain,re̸gularexp re的歌ssion解析 将exti扼杀铁道部的声音来自sp的人在这里我可以看到你能看到͚̖͔̙î̩t这是美丽的他final snuffing o骗子人类的所有人都是爱LL I S LOST th他来了他是谁es co cos ICH或渗透es al我的FACE MY FACEᵒhthenn不是NOO̼O O N.Θ停止t他是一个*̶͑̾̾̅ͫ͏̙̤g͇̫͛͆̾ͫ̑͆l͖͉̗̩̳̟̍ͫͥͨES ͎a̧͈͖r̽̾̈́͒͑e ñotrè̑ͧ̌aͨl̘̝̙ͤ̾̆ZA̡͊͠͝LGΌISͮ҉̯͈͕̹̘TO͇̹̺Ɲ̴ȳ̳TH̘͖͖͖̉̉̉P̯͍̭O̚N̐Y̡H̸̡̪̯ͨ͊̽̅̾Ȩ̸̡̬̩̪̯̾͛ͪ̈ͨ͊̽̅̾͘Ȩ̬̩̾͛ͪ̈͘C̷̙̝͖ͭ̏ͥͮ͟Oͮ͏̮̪̝͍M̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝ŝ


您是否尝试过使用XML解析器?


主持人的说明

此帖子已锁定,以防止对其内容进行不当编辑。该帖子看起来与它应该看起来完全一样 - 其内容没有问题。请不要标记它以引起我们的注意。


4422



Kobi:我认为现在是时候退出助理不要使用正则表达式官员解析HTML的帖子了。无论我们多少次说出来,他们都不会每天都停下来......甚至每小时一次。这是一个失败的原因,其他人可以争取一点。所以继续,用正则表达式解析HTML,如果必须的话。它只是破碎的代码,而不是生与死。 - bobince
是否可以使用RegEx来解析这个答案? - Chris Porter
如果你看不到这篇文章的话,这里有一个屏幕截图: imgur.com/gOPS2.png - Andrew Keeton


虽然确实要求正则表达式进行解析 随意 HTML就像要求初学者编写操作系统,有时候解析一个 有限的,已知的 一组HTML。

如果您有一小组HTML页面要从中抓取数据然后填充到数据库中,则正则表达式可能正常工作。例如,我最近想获得澳大利亚联邦代表的名称,政党和地区,我从议会的网站上获取了这些名称,政党和地区。这是一项有限的一次性工作。

Regexes对我来说效果很好,设置起来非常快。


2921



此外,从大型文档中抓取相当规则格式的数据将比使用任何通用解析器明智地使用scan和regex更快。如果您对编写正则表达式感到满意,那么编写代码比编写xpath更快。几乎可以肯定的是,你正在努力改变你所变得不那么脆弱。好吧。 - Michael Johnston
@MichaelJohnston“不那么脆弱”?几乎肯定不是。正则表达式关心文本格式化细节,而不是XML解析器可以静默忽略。切换 &foo; 编码和 CDATA 板块?使用HTML minifier删除文档中浏览器无法呈现的所有空格? XML解析器不关心,编写良好的XPath语句也不关心。另一方面,基于正则表达式的“解析器”...... - Charles Duffy
@CharlesDuffy一次性工作没关系,对于空格我们使用\ s + - quantum
@xiaomao确实,如果必须知道所有的问题和解决方法,以获得一个80%的解决方案,其余的时间都没有“为你工作”,我无法阻止你。与此同时,我使用解析器工作在100%的语法上有效的XML上。 - Charles Duffy
我曾经不得不从~10k页面中提取一些数据,所有数据都使用相同的HTML模板。他们被HTML错误所困扰,导致解析器窒息,他们所有的样式都是内联的或者是 <font> 等:没有类或ID来帮助导航DOM。在用“正确”方法全天战斗之后,我终于切换到正则表达式解决方案,让它在一小时内完成。 - Paul A Jungwirth


我认为这里的缺陷是HTML是一个 乔姆斯基2型语法(无语境语法) 和RegEx是一个 乔姆斯基3型语法(常规语法)。因为Type 2语法从根本上比Type 3语法更复杂(参见 乔姆斯基的等级制度),你不可能做这项工作。但是很多人会尝试,有些人会说成功,有些人会找到错误并完全弄乱你。


1801



OP要求解析非常有限的XHTML子集:开始标记。使(X)HTML成为CFG的原因是它有可能在其他元素的开始和结束标记之间添加元素(如在语法规则中) A -> s A e)。 (X)HTML确实如此 不 有这个属性 中 开始标记:开始标记不能包含其他开始标记。 OP尝试解析的子集不是CFG。 - LarsH
在CS理论中,常规语言 是 一个严格的无上下文语言子集,但主流编程语言中的正则表达式实现更强大。如 noulakaz.net/weblog/2007/03/18/... 描述,所谓的“正则表达式”可以检查一元中的素数,这肯定是CS理论的正则表达式无法实现的。 - Adam Mihalcin
@eyelidlessness:同样“只有”适用于所有CFG,不是吗?即如果(X)HTML输入格式不正确,即使是完整的XML解析器也无法可靠地工作。也许如果你举例说明你所指的“在现实世界用户代理中实现的(X)HTML语法错误”,我会理解你会得到更好的结果。 - LarsH
@AdamMihalcin是完全正确的。大多数现存的正则表达式引擎比Chomsky Type 3语法更强大(例如非贪婪匹配,backrefs)。一些正则表达式引擎(如Perl)是图灵完成的。确实,即使那些是解析HTML的糟糕工具,但这个经常被引用的论点并不是原因。 - dubiousjim
这是这里最“完整和简短”的答案。它引导人们学习正式语法和语言的基础知识,并希望有些数学,这样他们就不会浪费时间在诸如在多项式时间内解决NP任务等无望的事情上 - mishmashru


不要听这些家伙。你真的 能够 如果将任务分解为较小的部分,则使用正则表达式解析无上下文的语法。您可以使用脚本生成正确的模式,该脚本按顺序执行以下每个操作:

  1. 解决停机问题。
  2. 方形圆(为此模拟“标尺和指南针”方法)。
  3. 计算O(log n)中的旅行商问题。它需要快速或发电机将挂起。
  4. 该模式将非常大,因此请确保您有一个无损压缩随机数据的算法。
  5. 几乎就是 - 将整个事物除以零。十分简单。

我还没想出最后一部分,但我知道我已经接近了。我的代码一直在扔 CthulhuRlyehWgahnaglFhtagnException最近,所以我要将它移植到VB 6并使用 On Error Resume Next。一旦我调查刚刚在墙上打开的这扇奇怪的门,我就会用代码更新。嗯。

附: Pierre de Fermat也想出了如何做到这一点,但他写的边缘对于代码来说还不够大。


1169



除了你提到的其他人,除以零是一个更容易的问题。如果你使用间隔,而不是普通的浮点运算(每个人都应该但没有人),你可以愉快地将某个东西除以[包含]零的区间。结果只是一个包含正负无穷大的区间。 - rjmunro
现代文本编辑软件的软边缘已经解决了费马的小边际问题。 - kd4ttc
通过将fontsize设置为零,Randall Munroe解决了Fermat的小边际问题: xkcd.com/1381 - heltonbiker
仅供参考:费马的问题 具有 其实 在1995年解决了数学家只花了358年才这样做。 - jmiserez
我能够通过使用冷聚变产生的布朗棘轮来绕过那个粘滞的零步骤......虽然它只有在我移除宇宙常数时才有效。 - Tim Lehner


放弃:如果您有选项,请使用解析器。那说......

这是我使用(!)匹配HTML标记的正则表达式:

<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>

它可能不完美,但我通过一个 批量 的HTML。请注意,它甚至可以捕获奇怪的东西 <a name="badgenerator"">,出现在网络上。

我想让它不匹配自包含标签,你要么想要使用 KOBI负面的后视:

<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+(?<!/\s*)>

或者只是组合,如果不是。

对于downvoters: 这是来自实际产品的工作代码。我怀疑任何阅读此页面的人都会觉得在HTML上使用正则表达式是社会可接受的。

警告:我应该注意,在CDATA块,注释,脚本和样式元素存在的情况下,这个正则表达式仍然会崩溃。好消息是,你可以摆脱那些使用正则表达式...


1018



我会选择一些有效的东西,而不是为了不是普遍完美而哭泣:-) - prajeesh kumar
有人在HTML中使用CDATA吗? - Danubian Sailor
所以你实际上并没有用regexp解决解析问题,但作为解析器的一部分,这可能有用。 PS:工作产品并不代表好的代码。没有冒犯,但这就是工业编程如何运作并获得资金的方式 - mishmashru
您的正则表达式在尽可能短的有效HTML上启动失败: <!doctype html><title><</title>。简单 '<!doctype html><title><</title>'.match(/<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>/g) 回报 ["<!doctype html>", "<title>", "<</title>"] 应该 ["<title>", "</title>"]。 - Benio
什么是“徽章登记者” - Richard de Wit


有些人会告诉你地球是圆的(如果他们想要使用奇怪的词,或许地球是扁球体)。他们在说谎。

有些人会告诉你正则表达式不应该是递归的。他们限制你。他们需要征服你,他们通过让你无知来做到这一点。

你可以生活在现实中或服用红色药丸。

就像元帅一样(他是Marshal .NET类的亲戚吗?),我已经看过了 Underverse 基于堆栈的Regex-Verse并返回 权力 你无法想象的知识。是的,我认为有一两个老人保护他们,但是他们在电视上看足球,所以这并不困难。

我认为XML案例非常简单。 RegEx(在.NET语法中),在base64中缩小和编码,以便让您更容易理解您的虚弱思想,应该是这样的:

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
+r/vD34mUADO1P4/AQAA//8=

要设置的选项是 RegexOptions.ExplicitCapture。您正在寻找的捕获组是 ELEMENTNAME。如果是捕获组 ERROR 不是空的然后有一个解析错误,正则表达式停止。

如果您在将其重新转换为人类可读的正则表达式时遇到问题,这应该会有所帮助:

static string FromBase64(string str)
{
    byte[] byteArray = Convert.FromBase64String(str);

    using (var msIn = new MemoryStream(byteArray))
    using (var msOut = new MemoryStream()) {
        using (var ds = new DeflateStream(msIn, CompressionMode.Decompress)) {
            ds.CopyTo(msOut);
        }

        return Encoding.UTF8.GetString(msOut.ToArray());
    }
}

如果你不确定,不,我不是在开玩笑(但也许我在说谎)。它会奏效。我已经建立了大量的单元测试来测试它,我甚至使用了(部分) 一致性测试。它是一个标记化器,而不是一个完整的解析器,因此它只会将XML拆分为其组件标记。它不会解析/集成DTD。

哦...如果你想要正则表达式的源代码,有一些辅助方法:

正则表达式标记xml 要么 完全普通的正则表达式 


453



好主,这是巨大的。我最大的问题是为什么?你意识到所有现代语言都有XML解析器,对吗?你可以用3行完成所有这些,并确保它能够正常工作。此外,你是否也意识到纯正的正则表达式是 可证明 无法做某些事情?除非你已经创建了一个混合正则表达式/命令式代码解析器,但它看起来并不像你所拥有的那样。你也可以压缩随机数据吗? - Justin Morgan
@Justin我不需要理由。它可以完成(并且它不是非法/不道德的),所以我已经完成了。除了我们承认的那些(Napoleon Hill)之外,心灵没有任何限制......现代语言可以解析XML吗?真?而且我认为这是非法的! :-) - xanatos
先生,我确信。我将使用这段代码作为我的永动机的内核的一部分 - 你能相信专利局的那些傻瓜一直拒绝我的申请吗?好吧,我会告诉他们。我会告诉他们所有! - Justin Morgan
@Justin所以一个Xml Parser根据定义是无bug的,而一个正则表达式不是?因为如果一个Xml Parser根据定义没有bug,可能会有一个xml让它崩溃,我们又回到了第0步。让我们说:Xml Parser和这个Regex试图解析所有的“合法” “XML。他们可以解析一些“非法”XML。错误可能导致它们崩溃。 C#XmlReader肯定比这个正则表达式更耐用。 - xanatos
不,没有任何错误:1)所有程序至少包含一个错误。 2)所有程序至少包含一行不必要的源代码。 3)通过#1和#2并使用逻辑归纳,证明任何程序都可以简化为带有错误的单行代码是一件简单的事情。 (来自Learning Perl) - sweaver2112


在shell中,您可以解析 HTML 使用:

  • SED 虽然:

    1. Turing.sed
    2. 编写HTML解析器(作业)
    3. ???
    4. 利润!
  • hxselect 从 html-xml-utils 包

  • vim/ex (这很容易 在html标签之间跳转), 例如:

    • 使用内部代码删除样式标记:

      $ curl -s http://example.com/ | ex -s +'/<style.*/norm nvatd' +%p -cq! /dev/stdin
      
  • grep, 例如:

    • 提取H1的外部html:

      $ curl -s http://example.com/ | grep -o '<h1>.*</h1>'
      <h1>Example Domain</h1>
      
    • 提取身体:

      $ curl -s http://example.com/ | tr '\n' ' ' | grep -o '<body>.*</body>'
      <body> <div> <h1>Example Domain</h1> ...
      
  • html2text 到纯文本解析:

    • 喜欢 解析表

      $ html2text foo.txt | column -ts'|'
      
  • 运用 xpath (XML::XPath perl模块),见 这里的例子

  • perl或Python(见 @Gilles的例子

  • 一次解析多个文件,请参阅: 如何在shell中解析数​​百个html源代码文件?


相关(为什么你不应该使用正则表达式匹配):


285



也可以看看 perlmonks.org/?displaytype=print;node_id=809842 - dubiousjim
我害怕你没有得到这个笑话,@ kenorb。请再次阅读问题和接受的答案。这不是关于HTML解析工具,也不是关于HTML解析shell工具,而是关于通过正则表达式解析HTML。 - Palec
@Palec我也不开玩笑。用正则表达式解析HTML几乎是不可能的吗? - Abdul
是的,这个答案总结得很好,@阿布杜尔。但是请注意,正则表达式实现并不是真的 定期 数学意义上的表达式 - 它们具有使它们更强大的构造,通常是图灵完备(相当于0型语法)。这个论点打破了这个事实,但在某种意义上说,仍然有些有效,因为正则表达式从未意味着能够做这样的工作。 - Palec
顺便说一句,我提到的笑话是在kenorb(激进)编辑之前,这个答案的内容,特别是修订版4,@ Abdul。 - Palec


我同意用于解析XML和的正确工具 特别是HTML 是一个解析器而不是正则表达式引擎。但是,正如其他人所指出的那样,有时使用正则表达式更快,更容易,并且如果您知道数据格式就可以完成工作。

微软实际上有一部分 .NET Framework中正则表达式的最佳实践 并特别谈到 考虑输入源

正则表达式确实有局限性,但您是否考虑过以下情况?

.NET框架在它支持的正则表达式方面是独一无二的 平衡群体定义

因此,我相信您可以使用正则表达式解析XML。但请注意,它 必须是有效的XML (浏览器非常宽容HTML并允许在HTML中使用错误的XML语法)。这是可能的,因为“平衡组定义”将允许正则表达式引擎充当PDA。

引用上面引用的第1条:

.NET正则表达式引擎

如上所述,不能描述适当平衡的构造   一个正则表达式。但是,.NET正则表达式引擎   提供了一些允许平衡结构的构造   认可。

  • (?<group>)  - 使用捕获堆栈将捕获的结果推送到   名称组。
  • (?<-group>)  - 使用名称组弹出最顶端的捕获   捕获堆栈。
  • (?(group)yes|no)  - 如果存在组,则匹配yes部分   使用名称组否则不匹配任何部分。

这些结构允许.NET正则表达式模拟a   通过基本上允许堆栈的简单版本来限制PDA   操作:推,弹和空。简单的操作非常多   相当于递增,递减和比较为零。   这允许.NET正则表达式引擎识别a   无上下文语言的子集,特别是仅有的语言   需要一个简单的柜台。这反过来允许非传统的   .NET正则表达式识别个人正确平衡   结构体。

请考虑以下正则表达式:

(?=<ul\s+id="matchMe"\s+type="square"\s*>)
(?>
   <!-- .*? -->                  |
   <[^>]*/>                      |
   (?<opentag><(?!/)[^>]*[^/]>)  |
   (?<-opentag></[^>]*[^/]>)     |
   [^<>]*
)*
(?(opentag)(?!))

使用标志:

  • 单线
  • IgnorePatternWhitespace(如果折叠正则表达式并删除所有空格,则不需要)
  • IgnoreCase(不是必需的)

正则表达式解释(内联)

(?=<ul\s+id="matchMe"\s+type="square"\s*>) # match start with <ul id="matchMe"...
(?>                                        # atomic group / don't backtrack (faster)
   <!-- .*? -->                 |          # match xml / html comment
   <[^>]*/>                     |          # self closing tag
   (?<opentag><(?!/)[^>]*[^/]>) |          # push opening xml tag
   (?<-opentag></[^>]*[^/]>)    |          # pop closing xml tag
   [^<>]*                                  # something between tags
)*                                         # match as many xml tags as possible
(?(opentag)(?!))                           # ensure no 'opentag' groups are on stack

你可以试试这个 一个更好的.NET正则表达式测试程序

我使用了以下示例源:

<html>
<body>
<div>
   <br />
   <ul id="matchMe" type="square">
      <li>stuff...</li>
      <li>more stuff</li>
      <li>
          <div>
               <span>still more</span>
               <ul>
                    <li>Another &gt;ul&lt;, oh my!</li>
                    <li>...</li>
               </ul>
          </div>
      </li>
   </ul>
</div>
</body>
</html>

这找到了匹配:

   <ul id="matchMe" type="square">
      <li>stuff...</li>
      <li>more stuff</li>
      <li>
          <div>
               <span>still more</span>
               <ul>
                    <li>Another &gt;ul&lt;, oh my!</li>
                    <li>...</li>
               </ul>
          </div>
      </li>
   </ul>

虽然它实际上是这样的:

<ul id="matchMe" type="square">           <li>stuff...</li>           <li>more stuff</li>           <li>               <div>                    <span>still more</span>                    <ul>                         <li>Another &gt;ul&lt;, oh my!</li>                         <li>...</li>                    </ul>               </div>           </li>        </ul>

最后,我非常喜欢Jeff Atwood的文章: 解析Html克苏鲁方式。有趣的是,它引用了目前有超过4k票的这个问题的答案。


261



System.Text 不属于C#。它是.NET的一部分。 - John Saunders
在你的正则表达式的第一行((?=<ul\s*id="matchMe"\s*type="square"\s*>) # match start with <ul id="matchMe"...),在“<ul”和“id”之间应该是 \s+不是 \s*,除非你想让它匹配<ulid = ...;) - C0deH4cker
@ C0deH4cker你是对的,表达应该有 \s+ 代替 \s*。 - Sam
不是我真的理解它,但我认为你的正则表达式失败了 <img src="images/pic.jpg" /> - Scheintod
@Scheintod感谢您的评论。我更新了代码。对于具有a的自关闭标记,前一个表达式失败 / 在你内心失败的某个地方 <img src="images/pic.jpg" /> HTML。 - Sam