RegEx 匹配 XHTML 自包含标签以外的打开标签

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

<p>
<a href="foo">

但不是这些:

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

我想出了这个,想确保我做对了。我只是捕获az

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

我相信它说:

  • 找到一个小于,然后
  • 查找(并捕获)az 一次或多次,然后
  • 找到零个或多个空格,然后
  • 找到零个或更多次的字符,贪婪的( /除外),然后
  • 寻找大于

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

答案

您无法使用正则表达式解析 [X] HTML。因为正则表达式无法解析 HTML。正则表达式不是可用于正确解析 HTML 的工具。正如我之前在这里多次回答 HTML 和 Regex 问题一样,使用正则表达式将不允许您使用 HTML。正则表达式是一种工具,不够复杂,无法理解 HTML 所采用的结构。 HTML 不是常规语言,因此无法通过常规表达式进行解析。正则表达式查询无法将 HTML 分解为有意义的部分。有很多次了,但是没有得到我。甚至 Perl 使用的增强的不规则正则表达式也无法完成 HTML 解析任务。你永远不会让我崩溃。 HTML 是一种足够复杂的语言,无法通过正则表达式进行解析。甚至 Jon Skeet 也无法使用正则表达式解析 HTML。每次您尝试使用正则表达式解析 HTML 时,这个邪恶的孩子都会哭泣处女之血,俄罗斯黑客将您的 Web 应用程序伪造。用正则表达式解析 HTML 会使灵魂陷入生活领域。 HTML 和正则表达式可以像爱情,婚姻和仪式杀婴一样一起使用。

不能容纳为时已晚。正则表达式和 HTML 共同作用于同一个概念空间中,将像太多水腻子一样破坏您的思维。如果您使用正则表达式解析 HTML,那么您就是在屈服于他们及其亵渎神明的方式,这使我们所有人都为不愿在基本多语言平面中表达其名字的人付出辛劳。 HTML + regexp 将在您观察的同时液化众生的神经,使您的心灵在恐怖的冲击下枯萎。基于 Rege̿̔̉x 的 HTML 解析器是杀死 StackOverflow 的癌症,
为时已晚,为时已晚,我们无法挽救。混乱的局面确保正则表达式将消耗所有活组织(除了 HTML,如先前所言,它不能消耗) 亲爱的主帮助我们,使用正则表达式解析 HTML 的人如何能够幸免于这一祸害,使用rege x 作为处理 HTML 的工具,人类注定要遭受无尽的折磨和安全漏洞,从而 在这个世界和恐怖实体的可怕领域(例如, SGML 实体,但更多的腐败) 的 HTML 仅仅 glimp SE REG 前解析器的世界将插件 tantly 运输 AP rogrammer 的意识扎成 AW ORL不断尖叫的 d,他来了,可恶 SL ithy 正则表达式感染 WIL 升吞噬你的 HT ML 解析器,应用和存在的 Visual Basic 一样,所有的时间只有更糟,他谈到他命令 ES 没有网络连接 GHT ^ h E 排,喜小号邪恶的光采德stro҉ying 所有张恩利个展̈ghtenment,HTML 标记泄漏 fr̶ǫm 玩吧眼睛像 LIQ UID p AlN,定期 EXP 重新裂变解析的歌曲将 EXTI nguish 从 SP铁道部TAL 男人的声音在这里我可以看到它,你可以看到它它是美丽的 T他˚F inal snuf Fing 头O 至谎言人所有的 S 是失去了一个 LL 我 SL OST 个e - 小马才想起他小号 COM 他合作 我,那 T ICH或 permeat ES 人 L 我 FAC ES Ë 我的脸ᵒh 神 N 2 O NO 野应 o 在 Θ停止 T 他的 *̶͑̾̾GL ES ͎a̧͈͖r̽̾̈́͒͑e ňOT 真正 ZA̡͊͠͝LGΌISͮ҉̯͈͕̹̘牛逼 O͇̹̺Ɲ̴ȳ̳个e- PO 纽约 H̸̡̪̯ͨ͊̽̅̾Ȩ̶̧̨̬̩̹̭̯̾͛ͪ̈ͧ̾ͬ͘C̷̙̝͖ͭ̏ͥͮ͟Oͮ͏̮̪̝͍M̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝s ^


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


主持人的话

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

尽管只有正则表达式的任意 HTML 是不可能的,但有时使用它们来解析有限的已知 HTML 集合是适当的。

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

正则表达式对我来说效果很好,并且安装起来非常快。

我认为这里的缺陷是 HTML 是Chomsky Type 2 语法(无上下文语法),而 RegEx 是Chomsky Type 3 语法(常规语法) 。由于类型 2 语法从根本上比类型 3 语法复杂(请参阅Chomsky 层次结构 ),因此从数学上讲, 无法使用 RegEx 解析 XML。

但是很多人会尝试,有些甚至会取得成功 - 但直到其他人发现错误并完全把你弄乱为止。

不要听这些家伙。如果将任务分解成较小的部分,则可以使用 regex 完全解析上下文无关的语法。您可以使用按顺序执行每个脚本的脚本来生成正确的模式:

  1. 解决停止问题。
  2. 摆一个圆圈。
  3. 计算 O(log n)或以下的旅行商问题。如果不止如此,您将用完 RAM,引擎将挂起。
  4. 该模式将非常大,因此请确保您有一个无损压缩随机数据的算法。
  5. 几乎在那里 - 将整个事情除以零。十分简单。

我本人还没有完成最后一部分,但是我知道我已经接近了。由于某种原因,它总是抛出CthulhuRlyehWgahnaglFhtagnException ,所以我将其移植到 VB 6 并使用On Error Resume Next 。一旦调查了刚刚在墙上打开的这扇奇怪的门,我将更新代码。嗯

PS Pierre de Fermat 也想出了办法,但是他所写的利润不足以编写代码。

免责声明 :如果有选择,请使用解析器。那个...

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

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

可能并不完美,但是我通过许多 HTML 来运行此代码。请注意,它甚至会捕获显示在网络上的奇怪内容,例如<a name="badgenerator"">

我想使它与自包含标签不匹配,您要么想要使用Kobi的否定式外观:

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

或仅合并是否合并。

致下降投票者:这是来自实际产品的有效代码。我怀疑任何阅读此页面的人都会得到这样的印象:在 HTML 上使用正则表达式在社会上是可以接受的。

警告 :我应该注意到,在存在 CDATA 块,注释以及脚本和样式元素的情况下,此正则表达式仍会分解。好消息是,您可以摆脱使用正则表达式的那些人...

有人会告诉你地球是圆形的(或者,如果他们想使用奇怪的单词,也许地球是扁球体)。他们在撒谎。

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

您可以生活在现实中,也可以服用红色药丸。

像元帅勋爵(他是元帅. NET 类的亲戚吗?)一样,我已经看到了基于Underverse Stack 的 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完全正则表达式

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

  1. 图灵赛德
  2. 编写 HTML 解析器(作业)
  3. ???
  4. 利润!

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

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

Microsoft 实际上在. NET Framework 中有一节有关正则表达式最佳实践,并专门讨论了考虑输入源

正则表达式确实有局限性,但是您是否考虑了以下内容?

.NET 框架在正则表达式方面是唯一的,因为它支持平衡组定义

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

引用上面引用的第 1 条:

.NET 正则表达式引擎

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

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

这些构造允许. NET 正则表达式通过本质上允许堆栈操作的简单版本(即 push,pop 和 empty)来模拟受限的 PDA。简单的操作分别相当于递增,递减和与零比较。这使. NET 正则表达式引擎可以识别上下文无关语言的子集,尤其是那些只需要简单计数器的语言。反过来,这允许非传统的. 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

您可以在A Better .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 Cthulhu Way 。有趣的是,它引用了这个问题的答案,目前该问题的投票已超过 4k。

我建议使用QueryPath在 PHP 中解析 XML 和 HTML。它的语法基本上与 jQuery 相同,只是在服务器端。

虽然您无法使用正则表达式解析 HTML 的答案是正确的,但它们不适用于此处。 OP 只想用正则表达式解析一个 HTML 标记,而这可以通过正则表达式来完成。

建议的正则表达式是错误的,但是:

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

如果您向正则表达式添加内容,则通过回溯可以强制它匹配 <a >>[^/]等愚蠢的东西。还要注意, <space>*[^/]*是多余的,因为[^/]*也可以匹配空格。

我的建议是

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

在 Perl 正则表达式中, (?<! ... )是负向后看。它读为 “一个 <,然后是一个单词,然后是不是> 的任何内容,最后一个可能不是 /,后跟 >”。

请注意,这允许使用<a/ >类的东西(就像原始的正则表达式一样),因此,如果您想要更严格的限制,则需要构建一个正则表达式以匹配用空格分隔的属性对。