上下文
案例是使用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都失败了:
(?si)<tr.*?>(?!colspan)(.*?)</tr>
(?si)<tr.*?>(.*?)(?!colspan)</tr>
(?si)<tr.*?>.*?[^colspan].*?</tr>
(?si)<tr(\s[^>]*)?>.*?(?!colspan).*?</tr>
(?si)<tr(\s[^>]*)?>.*?(!colspan).*?</tr>
(?si)<tr(\s[^>]*)?>(.*?)(?!colspan)</tr>
(?si)<tr.*?>^(?!.*?colspan=").*?</tr>
How to negate specific word in regex?似乎有关系,但这些建议根本不会产生匹配。(?si)<tr.*?>(.(?<!colspan))*?</tr>
(?si)<tr.*?>(?!.*colspan).*</tr>
也没有使用http://www.regular-expressions.info/lookaround.html线索给出积极和消极的外观。我该如何正确编写此正则表达式?
答案 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>