2015-04-03 87 views
3

我的Python版本是2.7.6为什么re.findall('(ab)+','abab')返回['ab'] =与此同时re.findall('(ab)+?','abab')返回['ab','ab' ]?

我知道+?+的非贪婪版本。
,以便re.findall('(ab)+?', 'abab')尽可能少地匹配ab
结果['ab', 'ab']因此是有意义的。

但是当谈到贪婪版本匹配re.findall('(ab)+', 'abab')时,它让我困惑。
我认为贪婪的版本应该尽可能匹配ab
因此我得到['abab']
但我得到了['ab']

在re.findall()的帮助信息,它说:

Return a list of all non-overlapping matches in the string. 
If one or more groups are present in the pattern, return a 
list of groups; this will be a list of tuples if the pattern 
has more than one group. 

Empty matches are included in the result. 

这里我有两个组,为整个RE默认group0,我指定(ab)group1

所以我做了如下调查:

In [21]: ng = re.search('(ab)+?', 'abab') 

In [22]: g = re.search('(ab)+', 'abab') 

In [23]: ng.group(0) 
Out[23]: 'ab' 

In [24]: ng.group(1) 
Out[24]: 'ab' 

In [25]: g.group(0) 
Out[25]: 'abab' 

In [26]: g.group(1) 
Out[26]: 'ab' 

这是毋庸置疑的,re模块将匹配'abab'为GROUP0和'ab'作为组1的贪婪搜索。
但是为什么我在findall()操作时得到了['ab']而不是['abab', 'ab']
因为'abab'包含ab所以它们重叠,并且findall()只返回在这种情况下的最后一场比赛?

带着这样的疑问,我做了如下试验:

In [30]: g = re.findall('[A-z](ab)+', 'ababdab') 

In [31]: g 
Out[31]: ['ab', 'ab'] 

In [32]: dg = re.search('[A-z](ab)+', 'ababdab') 

In [33]: dg.groups() 
Out[33]: ('ab',) 

In [34]: dg.group() 
Out[34]: 'bab' 

现在,我现在是完全出我的脑海。
findall如何在这里工作?
为什么?

+1

**警告:不要在正则表达式中使用范围'[Az]'**它符合所有的ASCII字母,但它也匹配恰好位于'Z'和'a之间的几个标点符号'数字。 – 2015-04-03 12:33:56

回答

1

findall工作就像它应该工作:

  1. 它给所有的字符串中到结果列表中的比赛,如果没有捕捉组。
  2. 如果有一个捕获组,它将只返回一个捕获组列表。
  3. 如果有多个捕获组,则返回一个元组列表,其中一个元组包含一个匹配的捕获组。

接下来,只要有组的重复,MatchObject就会返回上次捕获的组。它在docs提到:

如果一组多次匹配,只有最后一场比赛是可访问:

>>> 
>>> m = re.match(r"(..)+", "a1b2c3") # Matches 3 times. 
>>> m.group(1)      # Returns only the last match. 
'c3' 

所以,两种现象的组合给您所遇到的结果。

-1

请看:

In [13]: re.findall('(ab)', 'ababab') 
Out[13]: ['ab', 'ab', 'ab'] 

In [14]: re.findall('(ab)+?', 'ababab') 
Out[14]: ['ab', 'ab', 'ab'] 

In [15]: re.findall('(ab)+', 'ababab') 
Out[15]: ['ab'] 

In[13]相当于In[14]。两种模式都将匹配每个ab组。然而,In[15]将匹配所有ab连续重复,无论其数量。

[A-z](ab)+模式意味着您想要以字母[A-z]开头的所有ab连续重复。在ababdab中匹配它的第一个组为bab:它以[0121]来自b,它位于[A-z]中,然后有一个以下ab组,结束于d,它开始下一个匹配组。

In [20]: re.findall('[A-z](ab)+', 'XababXabXab') 
Out[20]: ['ab', 'ab', 'ab'] 
+0

在关于**'[A-z]'**的问题下看到我的评论。我知道你只是从OP的代码中剪下来粘贴它,但你应该随时注意这样的错误,并在你回答时纠正它们。 (我们是全方位服务的专家。)通过不加评论地使用它们,您可以有效地认可它们。 (“呃,这个家伙似乎知道他在做什么,他用'[Az]'为什么我们不应该?”) – 2015-04-03 13:12:00

+0

我不认为是否应该使用'[Az]'范围正则表达式对原始问题和提出的测试用例都很重要。实际上,这与他们毫不相干。 – andref 2015-04-03 15:19:44

+0

所以你说在这种情况下可以使用'[A-z]',因为你知道该字符串不包含任何方括号,反斜线,插入符,下划线或反引号?当下一个正则表达式初学者出现并阅读你的答案时,他们应该如何知道这就是你的意思?它是**从来没有**好的在正则表达式中使用'[A-z]'。 – 2015-04-04 01:38:54

2

这里有一个微妙之处 - 在杰里的答案中提到,但没有明确说明。

您预计re.findall('(ab)+', 'abab')给大家介绍一下隐含什么,整个正则表达式匹配,“组1”括号“组0”。 这不是它的工作原理。如果有捕获圆括号,findall的列表只有包含捕获圆括号的组。观察:

>>> re.findall('(?:ab)+', 'abab') # no capture, reports group 0 
['abab'] 
>>> re.findall('(ab)+', 'abab') # one capture, reports _only_ group 1 
['ab'] 
>>> re.findall('((ab)+)', 'abab') # two captures, reports both groups 1 and 2 
[('abab', 'ab')]     # (but still not group 0) 

有关这方面的文档可能会更清晰。它假定你明白“组0”并不真正算作一个组。但是,这是RE图书馆数十年来的工作方式。