如何最佳化Python正則表示式的效能?


簡介

Python中有一個名為re 的特定於正則表示式的內建庫。你只需要匯入它就可以使用它的功能(例如search、match、findall等)。它們會為你返回一個Match物件,其中包含修改結果的有用技術。

根據維基百科,正則表示式(也稱為regexp)是指定搜尋模式的字元集合。它是一個工具,使你能夠過濾、提取或修改一系列字元。人們還發現,當使用“in”運算子時,正則表示式的執行速度更快。

正則表示式存在效能問題,通常難以除錯和維護。為了提高它們的效能,必須解決這些問題。

示例

import re my_string = 'I like tortilla.' # 'like (\w+)' is a regexp that matches 'like' followed by a space followed by # any number of word characters ('\w' means 'word character' and '+' means '1 or more'), # putting those word characters in a capture group (the parenthesis) regex_result = re.search(r'like (\w+)', my_string) print(regex_result.groups())

輸出

('tortilla',)

Soundex函式首先檢查輸入是否為非空的字母字串。最好的方法是什麼?

如果你回答“正則表示式”,那就去角落裡坐一會兒,反思一下你糟糕的直覺。正則表示式很少是正確的答案;應該儘可能避免使用它們。不僅是因為效能原因,還因為它們難以除錯和維護。同樣,也因為效能原因。

這段來自soundex/stage1/soundex1a.py的程式碼片段檢查函式引數source是否完全由字母組成的單詞,並且至少包含一個字母(不是空字串)−

為什麼正則表示式的效率很重要?

設計糟糕的正則表示式可能需要很長時間才能執行,並嚴重降低系統速度,即使精心設計的正則表示式可能非常有效。BMC Discovery已經過多次升級,使其比早期版本更能抵抗無效的正則表示式。

當應用於中等大小的字串時,設計一個需要花費數小時、數天甚至整個宇宙壽命才能完成的正則表示式是完全可能的。此外,它在多個處理器之間分配執行TPL模式的工作,以便即使一個處理器忙於冗長的正則表示式匹配,其他處理器也可以繼續工作。

低效正則表示式的構成

那麼,如何建立一個低效的常用短語呢?一個問題是當正則表示式回溯太遠時;如果正則表示式有幾個重複運算子,就會發生這種情況。+、*或n、m是重複運算子的示例。如果正則表示式進行了部分匹配但在之後失敗,則它必須迴圈返回並嘗試任何其他可能的區域性匹配,以防其中任何一個成功。

例如,考慮使用正則表示式a.*b.*cd匹配字串abc abc abc。由於字串中沒有d,因此匹配將永遠不會成功。但是,在放棄之前,正則表示式仍然必須窮盡字母組合a、b和c的所有可能性。

"*abc* abc abc",

"*ab*c ab*c* abc",
"*ab*c abc ab*c*",
"*a*bc a*bc* abc",
"*a*bc a*b*c ab*c*",
"*a*bc abc a*bc*",
"abc *abc* abc",
"abc *ab*c ab*c*",
"abc *a*bc a*bc*",
"abc abc *abc*"

作為一個粗略的指南,正則表示式需要執行的比較次數與字串的長度乘以可能的中間匹配數成正比。

在這個例子中,使用非貪婪運算子,即a.*?b.*?cd,對它將進行的匹配次數沒有影響,因為正則表示式引擎仍然需要嘗試每種組合。

編寫高效正則表示式的指南

考慮潛在的失敗情況

正如前面的例子所示,當正則表示式完全不匹配,但存在多個部分匹配時,問題就出現了。編寫正則表示式時,務必考慮正則表示式在失敗時的執行方式以及成功時的執行方式。

嘗試快速失敗

如果正則表示式到達無法匹配所需目標的點,請嘗試使整個正則表示式失敗。

分析——特別是失敗的案例

為了確保你的正則表示式匹配你預期的內容,驗證它是至關重要的。但是,對僅部分匹配它的長字串(例如兆位元組長的隨機字母字串)評估正則表示式的效率也很重要。

除非必要,否則不要使用分組

當你使用括號括起正則表示式的一部分時,正則表示式引擎必須更努力地儲存由該組匹配的文字,以防以後需要它。這可能會減慢匹配過程,有時會降低四倍或更多。

如果需要使用括號但不需使用組的內容,例如當正則表示式的一部分重複時,可以使用括號的非分組變體(?:)。

結論

有些人可能會反駁說,對於這類操作,Pandas更好。但是,我不認為它會像我們構建的純Python版本那樣快,因為它需要更長的時間才能將資料集載入到DataFrame中。

其他選項,例如使用regex庫或將資料分成多個部分並並行計數(一種與map-reduce相關的策略,這是大資料中非常相關的演算法),可以進一步提高速度。

更新於:2023年11月2日

3K+ 次瀏覽

啟動你的職業生涯

完成課程獲得認證

開始學習
廣告
© . All rights reserved.