2015-04-03 84 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圖書館數十年來的工作方式。