【问题标题】:Optional Capture Group Not Capturing可选捕获组未捕获
【发布时间】:2012-09-22 22:02:24
【问题描述】:
<tr><td align=right>Name:</td><td align=left><b><font color=black>Nathan</font></b></td></tr>
<tr><td align=right>Extension:</td><td align=left><b>222</b></td></tr>

我有上面的 HTML 文本(无法更改),我想要一个返回 3 个捕获组的正则表达式,标签 (Name|Extension) 字体颜色 (black|red)和数据(\w+)。

我在返回捕获组 2(字体颜色)时遇到了一些问题。如您所见,它不在表格的“扩展”行中,因此我将捕获组设为可选。当我这样做时,第一行根本不匹配。我尝试了很多不同的量词组合的试验和错误,但我仍然无法得到我正在寻找的结果。

这是我目前的模式:(Name|Extension):.*?(?:&lt;font color=(black|red)&gt;)?.*?&gt;(\w+)

我相信.*? 正在消耗可选的捕获组,并且仅匹配第 1 组和第 3 组。如果有人可以向我解释我哪里出错了,那就太好了。

编辑:作为一个想要了解更多关于正则表达式的人,如果人们可以将我上面的数据解释为不可变文本而不是 HTML,我将不胜感激。

【问题讨论】:

  • 不要使用正则表达式来检查 HTML。使用像 jsoup 这样的 HTML 解析器
  • @LuiggiMendoza 谢谢,很好的链接,但不幸的是我对应用程序没有创造性的控制,我无法添加新的依赖项。
  • 一定有办法使用jsoup或其他解析器。最后要做的事情可能是创建自己的解析器,但请相信我:如果你用正则表达式来做这件事,那将是一个地狱。
  • @LuiggiMendoza 我理解你的情绪,但不幸的是这不是我能控制的。让我们假设我只是尝试使用正则表达式来完成这个。我已经删除了 java 标签,希望这能让事情更清楚。
  • 这不是一种情绪,它表明您应该使用解析器而不是正则表达式:Parsing Html The Cthulhu Way。如果您仍然在寻找如何使用正则表达式来做到这一点,我祝您好运和喝咖啡。

标签: regex parsing


【解决方案1】:

问题在于不情愿的量词。第一个.*? 起初不消耗任何内容,允许正则表达式的下一部分尝试匹配: 之后的FONT 标签。它没有找到一个,但这没关系,因为那部分是可选的。然后第二个.*? 接管,只消耗它必须的量,直到&gt;(\w+) 可以匹配。因此,如果有 一个 FONT 标记,它会被第二个 .*? 匹配,而不是你想要的可选组。

但不要费心让量词变得贪婪;它可能工作,但更有可能只是失败效率较低。试试这个:

<td[^>]*>(Name|Extension):</td><td[^>]*><b>(?:<font color=(black|red)>)?([^<]*)<

因为我明确匹配了标签后面的所有标签,所以它在正确的位置匹配 FONT 标签(如果有的话)。如果它在那里,group(2) 将包含颜色;否则将是null。

【讨论】:

  • 谢谢 Alan,我感觉有些东西限制不够,导致我的字体标签被消耗,但你已经向我解释了到底发生了什么。在你的回答和 Aaron 的回答之间,我学到了更多关于正则表达式脆弱性的知识。
【解决方案2】:

这是你要找的暴行:

 (Name|Extension).*?<b>[<font color=]{0,12}(black|red)?>?(.*?)</.*

它非常脆弱,如果您处理的 HTML 格式与您提供的示例略有不同,我绝对不会期望它能够工作。不过,如果那个 HTML 可靠很糟糕,我认为你应该没问题。

请注意,这不能被视为Signor Mendoza 对使用正则表达式解析HTML 的固有不可能性的错误的证据;恰恰相反,这证明他在每一个细节上都是绝对正确的。这不是解析;这是作弊,就像我说的那样,只有当你使用的源 HTML 和你提供的示例一样丑陋时,你才能逃脱惩罚。 p>

测试用例:

 <tr><td align=right>Name:</td><td align=left><b><font color=black>Nathan</font></b></td></tr>
 <tr><td align=right>Extension:</td><td align=left><b>222</b></td></tr>
 <tr><td align=right>Name:</td><td align=left><b><font color=red>Thomas</font></b></td></tr>
 <tr><td align=right>Extension:</td><td align=left><b>223</b></td></tr>
 <tr><td align=right>Name:</td><td align=left><b><font color=black>Frank</font></b></td></tr>
 <tr><td align=right>Extension:</td><td align=left><b>224</b></td></tr>
 <tr><td align=right>Name:</td><td align=left><b><font color=red>Steve</font></b></td></tr>
 <tr><td align=right>Extension:</td><td align=left><b>225</b></td></tr>
 <tr><td align=right>Name:</td><td align=left><b><font color=black>Tony</font></b></td></tr>
 <tr><td align=right>Extension:</td><td align=left><b>226</b></td></tr>

结果:

 Name black Nathan
 Extension  222
 Name red Thomas
 Extension  223
 Name black Frank
 Extension  224
 Name red Steve
 Extension  225
 Name black Tony
 Extension  226

【讨论】:

  • 谢谢亚伦,这太完美了。我同意我处理的源 HTML 很糟糕(运气好的话,确实如此),我也同意 Luigi 的观点,即解析器会好得多,但感谢您回答我的问题。 [&lt;font color=]{0,12}你说?我今天学到了一个新技巧。
  • @Nathan:不,你没有。 [&lt;font color=]{0,12} 最多只能匹配任意十二个字符,&lt;、f、o 等。这绝对没有意义。
  • @AlanMoore 感谢您阐明了我对正则表达式中字符集的最初理解。虽然他的表达确实有效,所以很有帮助,但我已将您的表达标记为真实答案。
猜你喜欢
  • 1970-01-01
  • 2017-08-03
  • 1970-01-01
  • 1970-01-01
  • 2018-07-19
  • 2016-01-04
  • 2013-03-06
  • 2015-12-04
相关资源
最近更新 更多