首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么re.findall('(ab)+','abab')返回['ab']=同时re.findall('(ab)+?','abab')返回['ab','ab']?

为什么re.findall('(ab)+','abab')返回['ab']=同时re.findall('(ab)+?','abab')返回['ab','ab']?
EN

Stack Overflow用户
提问于 2015-04-03 19:00:37
回答 3查看 202关注 0票数 3

我的python版本是2.7.6

我知道+?+的非贪婪版本。

因此re.findall('(ab)+?', 'abab')将尽可能少地匹配ab

因此,结果['ab', 'ab']是有意义的。

但当谈到贪婪的版本match re.findall('(ab)+', 'abab')时,它让我感到困惑。

我认为贪婪的版本应该尽可能多地匹配ab

因此,我将得到['abab']作为结果。

但我换成了['ab']

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

代码语言:javascript
复制
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,以及我指定的group1 (ab)

所以我做了以下调查:

代码语言:javascript
复制
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'作为group1进行贪婪搜索。

但是为什么我在做findall()操作的时候会用['ab']而不是['abab', 'ab']呢?

因为'abab'包含ab,所以它们是重叠的,而findall()在这种情况下只返回最后一个匹配?

对于这个问题,我做了以下测试:

代码语言:javascript
复制
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在这里是如何工作的?

为什么?

EN

回答 3

Stack Overflow用户

发布于 2016-01-19 03:22:11

这里有一个微妙的地方-在Jerry的回答中提到了,但没有清楚地说明。

您希望re.findall('(ab)+', 'abab')告诉您整个正则表达式匹配的隐式"group 0“和圆括号的"group 1”。并非如此。如果有捕获括号,则findall的列表只包含捕获括号的组。请注意:

代码语言:javascript
复制
>>> 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)

文档可以更清楚地说明这一点。它假设您理解"group 0“并不真正算作一个组。但这就是几十年来RE库的工作方式。

票数 2
EN

Stack Overflow用户

发布于 2015-04-03 19:13:33

findall就像它应该工作的那样工作:

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

接下来,只要有重复的组,MatchObject就会返回最后捕获的组。它在docs中提到过

如果一个组匹配多次,则仅最后一个匹配为accessible:

m = re.match(r"(..)+","a1b2c3") #匹配3次。>>> m.group(1) #仅返回最后一个匹配项。'c3'

因此,这两个现象的组合给出了你正在体验的结果。

票数 1
EN

Stack Overflow用户

发布于 2015-04-03 19:25:36

看一看:

代码语言:javascript
复制
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:它以A-z中的b开头,然后有一个以d结尾的ab组,它开始了下一个匹配组。

代码语言:javascript
复制
In [20]: re.findall('[A-z](ab)+', 'XababXabXab')
Out[20]: ['ab', 'ab', 'ab']
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29430909

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档