如何从匹配中排除包含开始和结束标记之间的特定字符串的表行?

时间:2011-03-02 22:53:24

标签: html regex

上下文 案例是使用QuotaXML SDK 1.6屏幕抓取网页内容,最终在仪表板和iPhone上显示数据。 此QuotaXML工具仅提供用于提取表数据的正则表达式。 QuotaXML使用三步法解析html表。  1.首先它识别表格,例如使用“(?si)<table.*?>(.*?)</table>”  2.在此解析表中的第二个标识行,如“(?si)<tr.*?>(.*?)</tr>”  3.在此行范围内的第三个,单个单元格被标识为“(?si)<tr.*?>(.*?)</tr>

问题 源html包含一些行,这些行不是相关数据,如使用colspan跨越整个表宽度的行或图像。 或者表包含与所需数据线无关的数据单元,例如呼叫详细记录,其中还包含对计划中的分钟数减去的免费电话的调用,在本例中为0800和00800号码。 换句话说,(.*?)可能与'colspan =''既不'>&gt; 0800'也'不匹配&gt; 00800'。

在代码中:

exclude:<tr><td colspan="2"></td></tr>
include:<tr><td><strong>Date</strong></td><td><strong>Time</strong></td></tr>
exclude:<tr><td>05-01-2011</td><td>08004913</td></tr>
include:<tr><td>05-01-2011</td><td>0123456789</td></tr>

完成家庭作业 即使尝试我的第一个(开始简单)尝试只排除colspan都失败了:

  1. (?si)<tr.*?>(?!colspan)(.*?)</tr>
  2. (?si)<tr.*?>(.*?)(?!colspan)</tr>
  3. (?si)<tr.*?>.*?[^colspan].*?</tr>
  4. (?si)<tr(\s[^>]*)?>.*?(?!colspan).*?</tr>
  5. (?si)<tr(\s[^>]*)?>.*?(!colspan).*?</tr>
  6. (?si)<tr(\s[^>]*)?>(.*?)(?!colspan)</tr>
  7. (?si)<tr.*?>^(?!.*?colspan=").*?</tr> How to negate specific word in regex?似乎有关系,但这些建议根本不会产生匹配。
  8. (?si)<tr.*?>(.(?<!colspan))*?</tr>
  9. (?si)<tr.*?>(?!.*colspan).*</tr> 也没有使用http://www.regular-expressions.info/lookaround.html线索给出积极和消极的外观。
  10. 我该如何正确编写此正则表达式?

2 个答案:

答案 0 :(得分:1)

你遇到的第一个问题是你的原始表达非常脆弱,因为“。*?&gt;”旨在匹配最早的“&gt;” - 但实际上会匹配以下“&gt;”如果表达式的其余部分失败并回溯。

使用类似“[^&gt;] *&gt;”的构造代替。

第二个问题是你误解了否定前瞻的含义:它没有检查给定的模式是否在它的位置之前没有发生 - 它正在查看它的位置,以检查模式是否未发生AT这个位置。

通过这两项更改,您的第一次尝试非常接近于解决您的测试用例:

$ pcretest
PCRE version 7.8 2008-09-05

  re> /(?si)<tr[^>]*>(?!.*(colspan|>0?0800))(.*?)<\/tr>/
data> <tr><td colspan="2"></td></tr>
No match
data> <tr><td><strong>Date</strong></td><td><strong>Time</strong></td></tr>
 0: <tr><td><strong>Date</strong></td><td><strong>Time</strong></td></tr>
 1: <unset>
 2: <td><strong>Date</strong></td><td><strong>Time</strong></td>
data> <tr><td>05-01-2011</td><td>08004913</td></tr>
No match
data> <tr><td>05-01-2011</td><td>0123456789</td></tr>
 0: <tr><td>05-01-2011</td><td>0123456789</td></tr>
 1: <unset>
 2: <td>05-01-2011</td><td>0123456789</td>

请注意,这仍然无法解决整个问题,因为字符串中稍后存在“colspan”或800数字会阻止匹配。您需要进一步的测试用例,例如:

$ pcretest
PCRE version 7.8 2008-09-05

  re> /(?si)<tr[^>]*>(?!.*(colspan|>0?0800))(.*?)<\/tr>/
data> <tr><td>05-01-2011</td><td>0123456789</td></tr><tr><td colspan="2"></td></tr>
No match

所以你需要确保负向前瞻永远不会越过下一个:

$ pcretest
PCRE version 7.8 2008-09-05

  re> /(?si)<tr[^>]*>(?!((?!<\/tr).)*(colspan|>0?0800))(.*?)<\/tr>/
data> <tr><td colspan="2"></td></tr>
No match
data> <tr><td><strong>Date</strong></td><td><strong>Time</strong></td></tr>
 0: <tr><td><strong>Date</strong></td><td><strong>Time</strong></td></tr>
 1: <unset>
 2: <unset>
 3: <td><strong>Date</strong></td><td><strong>Time</strong></td>
data> <tr><td>05-01-2011</td><td>08004913</td></tr>
No match
data> <tr><td>05-01-2011</td><td>0123456789</td></tr>
 0: <tr><td>05-01-2011</td><td>0123456789</td></tr>
 1: <unset>
 2: <unset>
 3: <td>05-01-2011</td><td>0123456789</td>
data> <tr><td>05-01-2011</td><td>0123456789</td></tr><tr><td colspan="2"></td></tr>
 0: <tr><td>05-01-2011</td><td>0123456789</td></tr>
 1: <unset>
 2: <unset>
 3: <td>05-01-2011</td><td>0123456789</td>

此时人们可能想知道RegExps是否是解决此特定问题的正确工具: - )

答案 1 :(得分:0)

我不知道这是否是失败的原因,但个别细胞不是tr。这应该工作

(?si)<td(?!colspan)>(.*)</td>