正则表达式提取重叠<p>标签间内容时匹配缺失的问题排查
问题说明
原始HTML片段:
...<p><noop><fademusic:23,0><26:1><wait:30> <speed:10><30:2><5D:1><color:3>August 3, 9:47 AM<b>District Court<b>Defendant Lobby No. 2<color:0><p><hidetextbox:1><5D:0> <speed:255><music:8,0><wait:30><26:0><bgcolor:513,1,31><wait:7> <person:0,0,0><bg:2><bgcolor:258,1,31><wait:15><wait:30><hidetextbox:0> <name:512><shake:30,0><color:2>(Boy am I nervous!)<color:0><p> <hidetextbox:1><wait:45><name:1792><hidetextbox:0><bgcolor:769,8,31> Wright!<p>...
需求:提取所有<p>标签之间的内容(前一个标签的结束标签同时是下一个标签的开始标签)。
当前Python代码:
filetext = open(fn).read() tag = '<p>' result = re.findall(tag+"(.*?)"+tag,filetext,re.DOTALL) print(result)
预期输出:
['<noop><fademusic:23,0><26:1><wait:30>\n<speed:10><30:2><5D:1><color:3>August 3, 9:47 AM<b>District \nCourt<b>Defendant Lobby No. 2<color:0>', '<hidetextbox:1><5D:0>\n<speed:255><music:8,0><wait:30><26:0><bgcolor:513,1,31><wait:7>\n<person:0,0,0><bg:2><bgcolor:258,1,31><wait:15><wait:30><hidetextbox:0>\n<name:512><shake:30,0><color:2>(Boy am I nervous!)<color:0>', '\n<hidetextbox:1><wait:45><name:1792><hidetextbox:0><bgcolor:769,8,31>\nWright!']
实际输出:
['<noop><fademusic:23,0><26:1><wait:30>\n<speed:10><30:2><5D:1><color:3>August 3, 9:47 AM<b>District \nCourt<b>Defendant Lobby No. 2<color:0>', '\n<hidetextbox:1><wait:45><name:1792><hidetextbox:0><bgcolor:769,8,31>\nWright!']
解决方案
原正则的问题在于:tag+"(.*?)"+tag会消耗掉匹配到的结束<p>标签,导致下一次匹配只能从该标签之后开始,直接跳过了中间的内容块。
可以用两种方法解决:
方法1:使用零宽断言修改正则
通过零宽断言匹配<p>标签的位置,不消耗标签本身,这样就能连续捕获所有内容块:
import re filetext = open(fn).read() tag = '<p>' # 后行断言匹配<p>之后的位置,先行断言匹配<p>之前的位置 result = re.findall(f'(?<={tag})(.*?)(?={tag})', filetext, re.DOTALL) print(result)
方法2:使用字符串分割(更直观)
直接用<p>分割字符串,取中间的非空部分即可:
filetext = open(fn).read() tag = '<p>' parts = filetext.split(tag) # 过滤空字符串,得到所有<p>之间的内容 result = [part for part in parts if part] print(result)
两种方法都能得到预期的输出结果。
内容的提问来源于stack exchange,提问作者WoweMain
相关产品推荐
相关产品推荐

