Python re.findall() 中的关于括号的坑

在 Python 中使用正则表达式进行匹配时,使用 re.search()re.findall() 时对正则表达式的处理有所不同。

例如使用正则表达式 ([0-9A-F]{2}:){5}[0-9A-F]{2} 匹配一个 MAC 地址,待处理的字符串为 12:34:56:78:90:AB 。

使用 re.search() 进行匹配:

1
2
3
import re
match = re.search('([0-9A-F]{2}:){5}[0-9A-F]{2}', '12:34:56:78:90:AB').group()
print(match)

结果为 ‘12:34:56:78:90:AB’ ,符合预期;

使用 re.findall() 进行匹配:

1
2
3
import re
match = re.findall('([0-9A-F]{2}:){5}[0-9A-F]{2}', '12:34:56:78:90:AB')
print(match)

结果为 [‘90:’],不符合预期。

主要原因是 re.findall() 在匹配的时候,返回的是括号所匹配到的结果,在这里是只返回 [0-9A-F]{2}: 的匹配结果,而且后面带有 {5} ,因此返回第五个符合的匹配;对于多个括号,则返回多个括号分别匹配到的结果;如果没有括号,则返回就返回整条语句所匹配到的结果。

解决方案是使用括号将整个正则表达式括起来,这样 re.findall() 将会从外到内将每一组括号匹配到的结果列出。

1
2
3
import re
match = re.findall('(([0-9A-F]{2}:){5}[0-9A-F]{2})', '12:34:56:78:90:AB')
print(match)

结果为 [(‘12:34:56:78:90:AB’, ‘90:’)] ,获取第一个元素即可。

实际上这是正则表达式所特有的 , 任何一门高级语言使用正则都满足这个特点:有括号时只能匹配到括号中的内容,没有括号(相当于在最外层增加了一个括号)。在正则表达式里面 “()” 代表的是分组的意思,一个括号代表一个分组,匹配是只能匹配到 ”()” 中的内容。