2013-09-25 85 views
1

我在python中編寫了一個簡單的腳本,它應該逐行掃描文件並匹配一對不同的正則表達式來重新格式化數據。它的工作原理是這樣的:緩慢的python解析腳本

with open(file) as f: 
    for line in f: 
     line = line.rstrip('\n') 
     parseA(line, anOutPutFile) or parseB(line, anOutPutFile) or parseC(line, anOutPutFile) or parseD(line, anOutPutFile) 

每一行可以是A,B,C,d線中的一個或沒有(大部分匹配A,第二最常見的是B,等等。),在這裏是一個例子parseX功能:

def parseA(line, anOutPutFile): 
    regex = '.*-' + bla + ' A ' + '.*\((\d+)\) (\d+) (\w+) (\d+)@(.+) .* (.*)' #(etc..) 
    m = re.match(regex, line) 
    if m: 
     out = 'A' + ',' + m.group(1) + ',' + m.group(2) + ',' + ... #etc 
     anOutPutFile.write(out) 
     return True 
    else: 
     return False 

我希望在「或」操作的短路會幫助,但劇本仍對大文件(例如,大小的文件〜1G)慢得令人難以置信,我是想知道是否有任何明顯而簡單的事情,我可以開始修改,這是非常低效的。例如re.compile(但文檔說,最近的正則表達式被緩存,我只有少數)?

感謝

基於評論BELOW

我改變了代碼首先使用連接,然後使用re.compile既不似乎已經加快此設置。它運行在50,000行的測試文件上,大約需要93秒鐘,時間爲1秒。這也是它在此測試文件之前所採取的。每個正則表達式中我有8到12個組,其中有5個組。這就是我改成的代碼:

regexA = re.compile('.*0' + bla + ' A ' + '.*\((\d+)\) (\d+) (\w+) (\d+)@(.+) .* (.*) .* .* foo=far fox=(.*) test .*') 
regexB = re.compile(#similar) 
regexC = re.compile('.*0' + bla + ' C ' + '.*\((\d+)\) (\d+) (\w+) (\d+)@(.+) foo=(\d+) foo2=(\d+) foo3=(\d+)@(.+) (\w+) .* (.*) .* .* foo4=val foo5=(.*) val2 .*') 
regexD = re.compile(#similar) 
regexE = re.compile(#similar) 

#include two of the regex above fully to get an idea of what they look like 
#now this is an example of one of the parse funcs for regexA 

def parseA(line,anOutputFile): 
    m = regexA.match(line) 
    if m: 
     out = ''.join(['A',',',m.group(1),',',m.group(2),',',#etc]) 
     anOutputFile.write(out) 
     return True 
    else: 
     return False 

也許與列表的連接不是你的意思?編譯5個正則表達式頂級沒有幫助。

+0

你第一次嘗試編譯你的正則表達式parseX發生嗎?見7.2.2節開頭(http://docs.python.org/2/library/re.html) – prgao

+0

我不是因爲它說最近使用過的那些被緩存,我只有少數,但我試圖無論如何,以確保。 –

+0

對於例如'mmap'文件,然後're.finditer'所有A匹配,然後所有B匹配,等等,而不是調用're.match' 100M次,可能會快很多。如果你需要以正確的順序交錯線條,但是仍然可行,那將會有點棘手。 – abarnert

回答

0

你有沒有想過把文件寫出功能和簡化,因爲他們似乎都是一樣的。

將行和編譯的正則表達式作爲參數的解析函數。

def parse(line, regex, label): 
    m = regex.match(line) 
    if m: 
     return ','.join([label] + m.groups()) 

然後寫文件可以在主迴路

with open(file) as f: 
    for line in f: 
     line = line.rstrip('\n') 
     outline = parse(line, regexA, 'A') or parse(line, regexB, 'B') or parse(line, regexC, 'C') or parse(line, regexD, 'D') 
     if outline: 
      anOutPutFile.write(outline) 
+0

哦,這太漂亮了,我猜這是有效的,因爲None評估結果爲False –

+0

@Palace肯定,但它有速度優勢嗎? –

-1

讓所有的parseA,parseB調用or'ed對方沒有一個if仍然會執行其中的每一個。將if放在行的開頭,如果需要,只需執行pass,以防止在先前成功執行下一個parseX函數或創建ifs樹。

+0

我認爲'或'運營商短路,並會停止第一次真正的回報? –

+0

這個答案是錯誤的,或**做**短路。 http://stackoverflow.com/questions/2580136/does-python-support-short-circuiting –

+0

@PalaceChan和Graem Stuart,杜,從來沒有,我沒有看到parseX函數中的返回語句...你是那麼絕對正確。 –