如何最佳化 Python 正則表示式的效能?
簡介
在 Python 中,存在一個名為 re 的特定於 正則表示式 的內建庫。您只需要匯入它即可使用其功能(例如搜尋、匹配、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 相關的策略,這是 大資料 中非常相關的演算法)。
資料結構
網路
關係型資料庫管理系統
作業系統
Java
iOS
HTML
CSS
Android
Python
C 程式設計
C++
C#
MongoDB
MySQL
Javascript
PHP