2013-08-25 106 views
5

我有一個文件,其中包括一堆像「size = XXX;」的字符串。我第一次嘗試python的re模塊,並被以下行爲迷惑了一下:如果我在正則表達式中使用'or'管道,我只能看到匹配的那一點返回。例如:re.findall沒有返回完全匹配?

>>> myfile = open('testfile.txt','r').read() 
>>> print re.findall('size=50;',myfile) 
['size=50;', 'size=50;', 'size=50;', 'size=50;'] 
>>> print re.findall('size=51;',myfile) 
['size=51;', 'size=51;', 'size=51;'] 
>>> print re.findall('size=(50|51);',myfile) 
['51', '51', '51', '50', '50', '50', '50'] 
>>> print re.findall(r'size=(50|51);',myfile) 
['51', '51', '51', '50', '50', '50', '50'] 

匹配的「size =」部分消失了。 (但它肯定用於搜索,否則會有更多結果)。我究竟做錯了什麼?

回答

19

你的問題是,如果re.findall嘗試匹配正則表達式捕獲組(即包含在括號中的正則表達式的部分),那麼它是返回的組,而不是匹配的字符串。

解決此問題的一種方法是使用非捕獲組(前綴爲?:)。

>>> import re 
>>> s = 'size=50;size=51;' 
>>> re.findall('size=(?:50|51);', s) 
['size=50;', 'size=51;'] 

如果re.findall嘗試匹配正則表達式不捕獲任何東西,它返回整個匹配字符串。

儘管在此特定情況下使用character classes可能是最簡單的選項,但非捕獲組提供了更一般的解決方案。

2

'size=(50|51);'意味着你正在尋找size=50size=51但只有符合5051部分(注意括號),因此它不會返回sign=

如果你想sign=回來了,你可以這樣做:

re.findall('(size=50|size=51);',myfile) 
+2

'(...)'定義了一個匹配組。你也可以使用'(size =(50 | 51))',你可以有兩個匹配組,第一個是全尺寸= 5X,第二個只是5X部分。 – korylprince

1

我想你想要的是使用[]而不是()。 []指示字符集while()指示組匹配。嘗試是這樣的:

print re.findall('size=5[01];', myfile) 
+0

是剛剛編輯,thx – marcadian

+0

有幫助,雖然我構建到更復雜的正則表達式,我將需要() –

5

當正則表達式包含括號,他們捕捉其內容到組,改變findall()行爲只返回那些組。下面是從the docs相關部分:

(...)

匹配任何正則表達式的括號內, 並指示開始和一組結束; 組的內容可以在執行匹配後檢索到,並且可以在後面的字符串中與\number特殊序列匹配,下面描述了 。要匹配文字'('')',請使用\(\),或者將它們包含在字符類[(] [)]內部 。

爲了避免這種情況,你可以使用一個非捕獲組:

>>> print re.findall(r'size=(?:50|51);',myfile) 
['size=51;', 'size=51;', 'size=51;', 'size=50;', 'size=50;', 'size=50;', 'size=50;'] 

再次,從文檔:

(?:...)

一個非捕獲正則括號的版本。匹配括號內的任何正則表達式,但匹配的子字符串在執行匹配或稍後引用模式後無法檢索。