正则表达式使用|匹配异常:为何findall分组结果不符合预期?
|时re.findall结果不符合预期? 我来给你拆解这个问题的核心原因,以及对应的解决思路:
问题根源:正则分支的匹配逻辑
你写的r'(.*):|:(.*)'属于分支选择正则,正则引擎处理这类表达式时,会按顺序尝试每个分支——只要前面的分支匹配成功,就直接跳过后面的分支,不会再触发后续匹配逻辑。
拿你的字符串s6 = '''Male : abc Male : def'''举例:
- 第一个匹配片段是
Male :,这里第一个分支(.*):已经完全匹配了这个部分((.*)捕获到Male,随后匹配:),所以第二个分支:(.*)根本没机会执行。 - 第二个匹配片段是
Male :,同样被第一个分支优先匹配,第二个分支全程没发挥作用。
而re.findall的规则是:如果正则包含多个分组,会把每个匹配中所有分组的结果打包成元组返回;没被匹配到的分组,就用空字符串填充。这就是你得到[('Male ', ''), (' Male ', '')]的原因——只有第一个分支的分组有值,第二个分支的分组全程未匹配,结果都是空。
为什么单独用每个分支都正常?
单独用r'(.*):'时,它的作用是匹配所有:前面的内容;单独用r':(.*)'时,是匹配所有:后面的内容。这两种场景没有分支竞争,所以能得到你预期的部分结果。但一旦用|把它们合并,就变成了“要么匹配前面的,要么匹配后面的”,而非“同时匹配前后”,这和你的实际需求完全不符。
解决方案:把前后捕获整合到同一表达式里
你的需求是同时捕获:前后的内容,这时候不能用分支或,而是要把前后的捕获逻辑放到同一个正则模式里,让引擎一次性匹配到:的前后部分。
比如你可以这样写(既保留你想要的(.*)格式,又能准确捕获内容):
import re s6 = '''Male : abc Male : def''' # 用非贪婪匹配+边界限定,避免多余空格和误匹配 result = re.findall(r'(.*?)\s*:\s*(.*?)(?=\s+\w+:|$)', s6) print(result) # 输出 [('Male', 'abc'), ('Male', 'def')]
如果你的内容里没有特殊字符,也可以用更简洁的版本:
result = re.findall(r'(\w+)\s*:\s*(\w+)', s6)
这两种写法都能让正则引擎同时匹配:前后的内容,一次性捕获两个分组,完美符合你的预期。
总结一下:分支|是“二选一”的匹配逻辑,而你需要的是“同时匹配前后”,所以一定要把两个捕获分组放到同一个匹配分支里,不要用|分开它们。
内容的提问来源于stack exchange,提问作者sre

