2012-06-11 50 views
3

我正在研究一個應該匹配一系列作者的小Python腳本,我正在使用re模塊。我碰到什麼意外,我已經能夠將其降低到下面很簡單的例子:python match只捕獲第一組和最後一組 - 我誤解了什麼?

>>> import re 
>>> s = "$word1$, $word2$, $word3$, $word4$" 
>>> word = r'\$(word\d)\$' 
>>> m = re.match(word+'(?:, ' + word + r')*', s) 
>>> m.groups() 
('word1', 'word4') 

所以我確定我輸入的主要部分匹配的「基本」正則表達式,具有一定的識別特徵(在這種情況下,我使用了$ -signs),並且我嘗試匹配一個單詞加上可能的附加單詞列表。

我會預計m.groups()會一直顯示:

>>> m.groups() 
('word1', 'word2', 'word3', 'word4') 

但很顯然,我做錯了什麼。我想知道爲什麼這個解決方案不起作用,以及如何改變它,以便得到我期待的結果。順便說一句,這是在Linux機器上使用Python 2.6.6,以防萬一。

回答

6

儘管您正在匹配每個$word#$,但第二個捕獲組將不斷被匹配的最後一個項目替換。

讓我們來看看調試器:

>>> expr = r"\$(word\d)\$(?:, \$(word\d)\$)*" 
>>> c = re.compile(expr, re.DEBUG) 
literal 36 
subpattern 1 
    literal 119 
    literal 111 
    literal 114 
    literal 100 
    in 
    category category_digit 
literal 36 
max_repeat 0 65535 
    subpattern None 
    literal 44 
    literal 32 
    literal 36 
    subpattern 2 
     literal 119 
     literal 111 
     literal 114 
     literal 100 
     in 
     category category_digit 
    literal 36 

正如你所看到的,只有2個捕獲組:subpattern 1subpattern 2。每當發現另一個$word#$時,subpattern 2被覆蓋。

作爲一個潛在的解決方案,我會建議使用re.findall()代替re.match()

>>> s = "$word1$, $word2$, $word3$, $word4$" 
>>> authors = re.findall(r"\$(\w+)\$", s) 
>>> authors 
['word1', 'word2', 'word3', 'word4'] 
+1

感謝您的建議和額外的解釋 - 「re.DEBUG」是我的一個新選項;很高興知道! –

+1

@JakobvanBethlehem你也應該看看['re.VERBOSE'](http://docs.python.org/library/re.html#re.VERBOSE),它可以讓你拆分正則表達式,添加註釋等,仍然編譯它。基本上,在每行中寫入RE的部分內容,使用習慣的'#'添加註釋(並確保將其放在三個引號中)。當它們特別複雜時,可以使你的RE更具可讀性。 –

0

您可以避免正則表達式是這樣的:

>>> s = "$word1$, $word2$, $word3$, $word4$" 
>>> s.replace('$','').split() 
['word1,', 'word2,', 'word3,', 'word4'] 

使用正則表達式,你可以使用findall()代替:

>>> re.findall(word, s) 
['word1', 'word2', 'word3', 'word4'] 
+0

感謝看着我的問題。我意識到你提出的所有問題 - 我不能在我正在處理的全面案例中使用它們。 –

3

,我們在您的正則表達式只有兩個捕獲組。改爲嘗試。

重複捕獲由regex module支持。

+0

對於我正在嘗試處理的成熟案例,我真的不願意用'findall'去 - 感謝提示'正則表達式',也許這就是要走的路線 –

0

當你有可選的或重複捕獲組,如同你:

(?:, \$(word\d)\$)* 

正則表達式只具有儘管它匹配你的字符串的3個部分返回該組中拍攝到的文字一個地方,所以它包含最後的這樣的子字符串。

要查找所有子字符串,可以使用findall或在某個其他分隔符上標記字符串。

+0

謝謝你的建議 - 雖然在全部我試圖阻止使用'findall'(它實際上匹配我不想要的小塊和塊,它是使正常工作的正則表達式的其他部分的排序)也許我可以用我還沒有想到的方式解決它 –

+0

另一個解決方案是捕獲捕獲組中的整個可選部分,所以你有'\ $(word \ d)\ $((?:,\ $字\ d \ $)*)'。然後,你的正則表達式將返回兩個組,其中第一個單詞組「1」,其餘匹配組爲「2」,然後可以運行findall或split。這確保了第二個字符串至少遵循給定的模式。 – beerbajay

+0

感謝您對此的想法 - 這也是我一直在考慮的方向,所以我想我會試一試。 –

相關問題