为什么re.findall()找到比re.sub()更多的匹配?

时间:2013-05-04 06:52:54

标签: python regex

请考虑以下事项:

>>> import re
>>> a = "first:second"
>>> re.findall("[^:]*", a)
['first', '', 'second', '']
>>> re.sub("[^:]*", r"(\g<0>)", a)
'(first):(second)'

re.sub()的行为最初更有意义,但我也能理解re.findall()的行为。毕竟,您可以匹配first:之间的空字符串,该字符串仅由非冒号字符组成(恰好为零),但为什么re.sub()的行为方式不同? ?

最后一个命令的结果不应该是(first)():(second)()吗?

3 个答案:

答案 0 :(得分:7)

你使用允许空匹配的*:

'first'   -> matched
':'       -> not in the character class but, as the pattern can be empty due 
             to the *, an empty string is matched -->''
'second'  -> matched
'$'       -> can contain an empty string before,
             an empty string is matched -->''

引用documentation for re.findall()

  

结果中包含空匹配,除非它们触及另一场比赛的开头。

documentation for re.sub()

中解释了您未在子结果中看到空匹配的原因
  

仅当与前一个匹配不相邻时,才会替换模式的空匹配。

试试这个:

re.sub('(?:Choucroute garnie)*', '#', 'ornithorynque') 

现在这个:

print re.sub('(?:nithorynque)*', '#', 'ornithorynque')

没有连续的#

答案 1 :(得分:3)

由于某种原因,处理空匹配的算法是不同的。

findall的情况下,它的作用类似于(优化版本):对于每个可能的起始索引0&lt; = i&lt; = len(a),如果字符串在i匹配,则追加比赛;并且通过使用此规则避免重叠结果:如果在i处存在长度为m的匹配,则不要在i + m之前查找下一个匹配项。您的示例返回['first', '', 'second', '']的原因是,在firstsecond之后立即找到空匹配,但不会在冒号后找到 - 因为从该位置开始查找匹配将返回完整字符串second

sub的情况下,正如您所注意到的那样,区别在于它明确忽略了在另一个匹配后立即发生的长度为0的匹配。虽然我知道为什么这可能有助于避免sub的意外行为,但我不确定为什么存在这种差异(例如,为什么findall不会使用相同的规则。)

答案 2 :(得分:1)

import re
a = "first:second:three"
print re.findall("[^:]*", a)

返回匹配pattern的所有子字符串,这里给出

>>> 
['first', '', 'second', '', 'three', '']

sub()用于替换,并将替换最左边的非重叠模式。前

import re
a = "first:second:three"
print re.sub("[^:]*", r"smile", a)

给出

>>> 
smile:smile:smile

您可以使用第4个arg命令要替换的出现次数,count: