注意:這已經在python2.7上測試過。你可能需要調整python 3中的東西來處理字符串和字節,但是希望這不會太痛苦。內存映射文件可能不適合您的情況(32位模式增加沒有足夠的連續虛擬內存的機會,不能從管道或其他非文件等中讀取)。
下面是一個解決方案,一次讀取128k塊,只要您的正則表達式匹配比這個大小小的字符串,這將工作。另請注意,您不受限於使用單行正則表達式。這個解決方案運行得很快,但我懷疑它比使用mmap稍微慢一些。它可能更多地取決於你在比賽中所做的事情,以及你正在搜索的正則表達式的大小/複雜性。
該方法將確保在內存中只保留最多2個塊。在某些使用情況下,您可能希望強制每塊至少執行1次匹配作爲完整性檢查,但此方法會截斷以保留內存中最多2個塊。它還確保當前塊的結尾處的任何正則表達式匹配都不會生成,而是在真實輸入耗盡或正則表達式匹配之前匹配的另一個塊時保存最後一個位置,爲了更好地匹配「[^ \ n] +」或「xxx $」等模式。如果你看到正則表達式像xx(?!xyz)這樣的yx位於下一個塊中,但是在大多數情況下你可以使用這種模式來解決這個問題,你仍然可以打破它。
import re
def regex_stream(regex,stream,block_size=128*1024):
stream_read=stream.read
finditer=regex.finditer
block=stream_read(block_size)
if not block:
return
lastpos = 0
for mo in finditer(block):
if mo.end()!=len(block):
yield mo
lastpos = mo.end()
else:
break
while True:
new_buffer = stream_read(block_size)
if not new_buffer:
break
if lastpos:
size_to_append=len(block)-lastpos
if size_to_append > block_size:
block='%s%s'%(block[-block_size:],new_buffer)
else:
block='%s%s'%(block[lastpos:],new_buffer)
else:
size_to_append=len(block)
if size_to_append > block_size:
block='%s%s'%(block[-block_size:],new_buffer)
else:
block='%s%s'%(block,new_buffer)
lastpos = 0
for mo in finditer(block):
if mo.end()!=len(block):
yield mo
lastpos = mo.end()
else:
break
if lastpos:
block=block[lastpos:]
for mo in finditer(block):
yield mo
要測試/探索,你可以運行這個命令:
# NOTE: you can substitute a real file stream here for t_in but using this as a test
t_in=cStringIO.StringIO('testing this is a 1regexxx\nanother 2regexx\nmore 3regexes')
block_size=len('testing this is a regex')
re_pattern=re.compile(r'\dregex+',re.DOTALL)
for match_obj in regex_stream(re_pattern,t_in,block_size=block_size):
print 'found regex in block of len %s/%s: "%s[[[%s]]]%s"'%(
len(match_obj.string),
block_size,match_obj.string[:match_obj.start()].encode('string_escape'),
match_obj.group(),
match_obj.string[match_obj.end():].encode('string_escape'))
這裏是輸出:
found regex in block of len 46/23: "testing this is a [[[1regexxx]]]\nanother 2regexx\nmor"
found regex in block of len 46/23: "testing this is a 1regexxx\nanother [[[2regexx]]]\nmor"
found regex in block of len 14/23: "\nmore [[[3regex]]]es"
這可與快速分析大量的XML,其中結合使用它可以根據一個子元素分解爲微型DOM,而不必在使用SAX解析器時深入處理回調和狀態。它還允許您更快地過濾XML。但是我也將它用於其他許多用途。我有點驚訝的食譜,這不是更容易在網上提供!
還有一件事:只要傳入的流正在生成unicode字符串,並且如果使用像\ w這樣的字符類,則需要將re.U標誌添加到re.compile模式構建。在這種情況下,block_size實際上是指字符數而不是字節數。
你能展示一個你想做什麼的更完整的例子嗎?隨着一些樣本輸入和輸出一起。 – 2011-02-14 05:50:23