2013-02-07 61 views
4
正則表達式

我通過道格·海爾曼的「Python標準庫的示例」工作和整個這個傳來:編譯在Python

「1.3.2編譯表達式 再包括模塊級功能使用正則表達式作爲文本字符串,但編譯程序使用頻繁的表達式更有效。「

我無法按照他的解釋爲什麼這是這種情況。他表示,「模塊級函數維護一個編譯表達式的緩存」,並且由於「緩存的大小」是有限的,「使用編譯表達式直接避免了緩存查找開銷。」

如果有人能夠請解釋或指導我解釋一下,我可以更好地理解爲什麼編譯程序常用的正則表達式以及該過程如何實際工作更有效率,我將不勝感激。

回答

7

嗯。這很奇怪。我的知識至今(上漲,以及其他來源,from this question)建議我最初的回答:


先回答

Python中緩存你最近使用過的100個正則表達式,所以即使你不把它們編譯明確地說,它們不必在每次使用時重新編譯。

但是,有兩個缺點:當達到100個正則表達式的限制時,整個高速緩存會被燒燬,所以如果在一行中使用101個不同的正則表達式,則每次都會重新編譯每一個正則表達式。那麼,這是不太可能的,但仍然。第二,爲了找出一個正則表達式是否已經被編譯過,解釋器每次需要在緩存中查找正則表達式,這需要花費一些額外的時間(但由於字典查找速度非常快,所以不會太多) 。

所以,如果你明確地編譯你的正則表達式,你會避免這個額外的查找步驟。


更新

我只是做了一些測試(Python的3.3):

>>> import timeit 
>>> timeit.timeit(setup="import re", stmt='''r=re.compile(r"\w+")\nfor i in range(10):\n r.search(" jkdhf ")''') 
18.547793477671938 
>>> timeit.timeit(setup="import re", stmt='''for i in range(10):\n re.search(r"\w+"," jkdhf ")''') 
106.47892003890324 

所以這樣看來,沒有緩存正在做。也許這是timeit.timeit()運行的特殊情況的怪癖?

在另一方面,在Python 2.7,不同的是沒有明顯的:

>>> import timeit 
>>> timeit.timeit(setup="import re", stmt='''r=re.compile(r"\w+")\nfor i in range(10):\n r.search(" jkdhf ")''') 
7.248294908492429 
>>> timeit.timeit(setup="import re", stmt='''for i in range(10):\n re.search(r"\w+"," jkdhf ")''') 
18.26713670282241 
+0

謝謝蒂姆!我把這個和你新發布的關於這個問題的問題聯繫起來了。這非常有用 - 非常感謝! – user7186

4

我相信他想說的是你不應該在你的循環中編譯你的正則表達式,而是在它之外。然後您可以在循環內運行已編譯的代碼。

代替:

while true: 
    result = re.match('A', str) 

你應該把:

regex = re.compile('A') 
while true: 
    result = regex.match(str) 

基本上 re.match(pattern, str)結合了編譯和匹配步驟。在循環內部編譯相同的模式效率低下,因此應該在循環之外提升。

查看Tim的正確推理的答案。

+0

這是不正確的。 Python編譯每個正則表達式並緩存它們以供以後重用,所以它們在每次迭代中都不重新編譯。通過預編譯正則表達式,您唯一可以避免的是每次迭代的緩存查找。 –

+0

@TimPietzcker我剛剛開始研究Python,所以我想我知道我在說什麼。謝謝你糾正我。 – Michael

+0

我只是做了一些測試,看來我的回答並不完全正確。我會進一步研究。 –

0

這聽起來我像筆者簡單地說這是更高效的編譯正則表達式並保存比來算在它之前編譯的版本上仍然保存在模塊的有限尺寸的內部緩存中。這可能是因爲編譯它們所花費的工作量以及必須首先發生的額外緩存查找開銷大於客戶端僅僅存儲它們本身。