Python 正则表达式 - re.search() 与 re.findall() 的区别

29 投票
2 回答
31006 浏览
提问于 2025-04-17 11:02

我在学校要写一个Python的正则表达式脚本,用来提取IP地址。我用的这个正则表达式在re.search()里好像能正常工作,但在re.findall()里却不行。

exp = "(\d{1,3}\.){3}\d{1,3}"
ip = "blah blah 192.168.0.185 blah blah"
match = re.search(exp, ip)
print match.group()

每次匹配到的都是192.168.0.185,但当我用re.findall()时结果却不一样。

exp = "(\d{1,3}\.){3}\d{1,3}"
ip = "blah blah 192.168.0.185 blah blah"
matches = re.findall(exp, ip)
print matches[0]

0.

我在想,为什么re.findall()的结果是0,而re.search()的结果却是192.168.0.185,明明我在两个函数里用的是同一个表达式。

我该怎么做才能让re.findall()正确地按照这个表达式来提取呢?或者我是不是哪里搞错了?

2 个回答

6

你在这个正则表达式中只捕捉到了最后的0。

你需要修改这个表达式,以便捕捉到整个IP地址,并把重复的部分设置为不捕捉的组:

In [2]: ip = "blah blah 192.168.0.185 blah blah"

In [3]: exp = "((?:\d{1,3}\.){3}\d{1,3})"

In [4]: m = re.findall(exp, ip)

In [5]: m
Out[5]: ['192.168.0.185']

In [6]: 

如果这有助于理解正则表达式的话:

In [6]: re.compile(exp, re.DEBUG)
subpattern 1
  max_repeat 3 3
    subpattern None
      max_repeat 1 3
        in
          category category_digit
      literal 46
  max_repeat 1 3
    in
      category category_digit

这里解释了子模式。子模式1是通过findall捕捉到的内容。

19

findall这个函数会返回一个匹配结果的列表,文档中提到:

如果模式中有一个或多个分组,返回的将是一个分组的列表;如果模式有多个分组,返回的将是一个元组的列表。

所以,你之前的表达式有一个分组,在字符串中匹配了3次,最后一次匹配的结果是0.

要解决你的问题,可以使用:exp = "(?:\d{1,3}\.){3}\d{1,3}";通过使用非分组的版本,就不会返回分组,所以在这两种情况下都能得到匹配结果。

撰写回答