为何用Regex匹配含<br>的<span>元素时出现异常匹配?
为什么你的正则会匹配跨
<span>的内容? 这其实是正则非贪婪匹配的一个典型陷阱,我来给你一步步拆解原因:
先看你的原始场景
你的目标字符串是:
xx= '<div> <span>123</span> <span>456 <br> 789</span> </div>'
第一个正则能正常工作的原因
你用<span>.*?</span>时,.*?是非贪婪匹配,它会尽可能少地匹配字符,直到遇到第一个</span>就停止。因为每个<span>内部没有嵌套的<span>或</span>标签,所以它能精准拆分出两个独立的<span>元素。
第二个正则出问题的核心
当你换成<span>.*?<br>.*?</span>时,问题出在.*?的匹配规则上:
正则里的.默认会匹配除换行外的任意字符——包括HTML标签本身(比如</span>、<span>这些字符串都会被当成普通字符匹配)。
具体匹配过程是这样的:
- 正则从第一个
<span>开始匹配,第一个<span>内部没有<br>,所以.*?会一直往后“搜索”<br>; - 它会跳过第一个
</span>、第二个<span>的起始标签,直到找到目标<br>; - 接着后面的
.*?匹配到最近的</span>,最终就把从第一个<span>到最后一个</span>的整个片段都当成了一个匹配结果。
怎么修复这个正则?
你需要限制.*?不能跨<span>标签匹配,这里可以用负向预查来实现,修改后的正则如下:
re.findall(r'<span>(?:(?!</?span>).)*?<br>(?:(?!</?span>).)*?</span>', xx)
这里的(?:(?!</?span>).)是关键:它表示“当前位置后面不是<span>或</span>的任意单个字符”,这样就把匹配范围牢牢限制在单个<span>内部了,不会跨标签匹配。
额外小提醒
虽然你知道正则解析HTML不是规范做法,但还是建议试试BeautifulSoup——它对不规范HTML的容错性比lxml更强,用它来筛选包含<br>的<span>会比正则靠谱得多,代码也更易维护。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

