2010-03-29 23 views
3

我對Python很新,對於正則表達式來說還是比較新的。 (我沒有Perl的經驗。)如何提高我的Python正則表達式語法?

我能夠使用正則表達式的方式,但我不確定我的代碼是特別Pythonic或consise。例如,如果我想讀一個文本文件並打印出在每行中的'foo'和'bar'之間直接出現的文本(假設這發生了一行或零行),我會寫如下:

fileList = open(inFile, 'r') 
pattern = re.compile(r'(foo)(.*)(bar)') 
for line in fileList: 
    result = pattern.search(line) 
    if (result != None): 
     print result.groups()[1] 

有沒有更好的方法?需要if以避免在None上撥打groups()。但我懷疑有一個更簡潔的方式來獲得匹配的字符串,當沒有錯誤時不會拋出錯誤。

我不希望Perl類似不可讀。我只想以最簡單最普通的方式完成這項共同任務。

回答

3

我覺得很好。

一些小點: -

  • 您可以result.group(x+1)取代result.groups()[x]
  • 如果您不需要捕獲foobar,只需使用r'foo(.*)bar'即可。
  • 如果您使用的是Python 2.5+,請嘗試使用the with statement,這樣即使有異常情況下文件可以正常關閉。

順便說一句,作爲5班輪(不是我推薦這個):

import re 
pattern = re.compile(r'foo(.*)bar') 
with open(inFile, 'r') as fileList: 
    searchResults = (pattern.search(line) for line in fileList) 
    groups = (result.group(1) for result in searchResults if result is not None) 
    print '\n'.join(groups) 
+0

出於某種原因,'result.group(1)'爲我捕獲'foo',但'result.group(2)'工作。 – 2010-03-29 10:12:16

+0

@FarmBoy:因爲你用'(foo)(。*)(bar)'而不是'foo(。*)bar'匹配。 – kennytm 2010-03-29 12:46:15

+0

元組索引不是基於0的嗎?我期待'result.group(0)'會在我的代碼中返回'foo'。 – 2010-03-29 16:01:35

0

你不需要正則表達式。在「bar」上分割你的字符串,迭代它們,找到「foo」,在「foo」上做一個分割,並把結果向右。當然,你可以使用其他字符串操作,如獲取索引和東西。

>>> s="w1 w2 foo what i want bar w3 w4 foowhatiwantbar w5" 
>>> for item in s.split("bar"): 
...  if "foo" in item: 
...   print item.split("foo")[1:] 
... 
[' what i want '] 
['whatiwant'] 
1

有兩種技巧:第一種是re.finditer正則表達式函數(和方法)。 第二個是使用mmap模塊。

從上re.DOTALL的文檔,我們可以注意到,.不匹配換行符:

沒有這個標誌, ''將匹配除換行符之外的任何內容。

所以,如果你在文件的任何地方尋找所有的比賽(如當讀取到使用f.read()字符串),你可以假裝每一行是一個孤立子(注:這並不完全正確,但如果你希望^和$斷言以這種方式工作,請使用re.MULTILINE)。現在,因爲您注意到我們假設每行只有零個或一個事件,所以我們不必擔心re.finditer()比它應該更多(因爲它會!)。因此現在,你可以(),而不是替換所有以迭代超過finditer:

fileList = open(inFile, 'r') 
pattern = re.compile(r'foo(.*)bar') 
for result in pattern.finditer(fileList.read()): 
    print result.groups(1) 

這不是真的不錯不過。這裏的問題是整個文件被讀入內存以方便您。如果有一種方便的方式來做到這一點,而不會破壞較大的文件,那會很好。而且,那就是!輸入mmap模塊。

mmap讓你把文件看作是一個字符串(一個可變字符串,不能少!),並且它不會將整個東西加載到內存中。長期和短期的是,你可以使用下面的代碼來代替:

fileList = open(inFile, 'r+b') 
fileS = mmap.mmap(fileList.fileno(), 0) 
pattern = re.compile(r'foo(.*)bar') 
for result in pattern.finditer(fileS): 
    print result.groups(1) 

和它的作用是相同的,但沒有一次(希望)消耗整個文件。

0

我有一些小建議:

  • 除非你確信foobar可發生不超過每行一次,它的更好,如果你需要使用的.*?代替.*
  • 確保foobar只應作爲整個單詞匹配(而不是foonlyrebar),你應該添加他們(\bfoo\b等)
  • 周圍 \b
  • 您可以使用lookaround來僅匹配匹配本身((?<=\bfoo\b).*?(?=\bbar\b)),所以現在result.group(0)將包含匹配項。但這不是更可讀:)