天天看點

正規表達式的效率與優化

不同語言中有不同實作和限制,是以下面一些原則隻是最基本的原則,不保證在所有實作中通用。有時候,有一種實作會對預知的情況進行優化,而另一種則不會。也就是說,正規表達式的效率不僅和正則引擎的種類相關,還和引擎具體實作有關。

1、使用字元組代替分支條件。

比如,使用[a-d]表示a~d之間的字母,而不是使用(a|b|c|d)。

2、優先選擇最左端的比對結果。

這在介紹分支條件比對郵編的時候已經提到過。對于傳統型NFA引擎來說,這樣改動對正則比對的效果是有利的,因為引擎一旦找到比對結果就會停下來,而不會去嘗試正規表達式的每一種可能(PHP中的preg函數就屬于傳統型NFA引擎)。

3、标準量詞是比對優先的。

若用量詞限制某個表達式,那麼在比對成功前,進行的嘗試次數有下限和上限。

4、謹慎用點元符号,盡可能不用星号和加好這樣的任意量詞。

隻要能确定範圍(例如“\w”),就不要用點号;隻要能夠預測重複次數,就不要用任意量詞。

5、盡量使用字元串函數處理代替。

使用字元串函數和正規表達式都可以處理字元串,兩者相比,字元串函數處理的效率更高。當然,有些情況幾乎是非正規表達式不能勝任的,或者不用正規表達式的成本太高,這些情況不得不用正規表達式,既然如此,就應該設計好。

6、合理使用括号。

每使用一個普通括号(),而不是非捕獲型括号(?:...),就會保留一部分記憶體等着再次通路。這樣的正規表達式、無限次的運作次數,無異于一根根稻草的堆加,終将把駱駝壓死。

7、起始、行描點優化。

能 确定起始位置,使用^能提高比對的速度。同理,使用$标記結尾,正則引擎則會從符合條件的長度處開始比對,略過目标字元串中許多可能的字元。在寫正則表達 式時,應該将描點獨立出來,例如”^(?:abc|123)比^123|abc“效率高,而”^(abc)比(^abc)"效率更高。

這個原則不适用于所有正則引擎。比如在PCRE中,二者效率相當。

8、量詞等價轉換的效率差異。

例如在PHP中,使用“\d\d\d”和“\d{3}”,或者“====”和“={4}”,他們之間的效率幾乎沒有差别。但是換用其他語言可能就會有比較明顯性能差異了。

9、對大而全的表達式進行拆分。

10、使用正則以外的解決方案。

前 面已經提到,在有的場合可以使用字元串來代替正規表達式,此外,還有其他方案可以代替正規表達式。例如,在某項目中需要分析PHP代碼,分離出對應的函數 調用(以及源代碼對應的位置)。雖然這是用正規表達式也可以使用,但無論從效率還是代碼複雜度方面考慮,這都不是最優的方式。PHP已經内置解析器的接口 PHP Tokenizer。

使用PHPTokenizer能簡單、高效、準确地分析出PHP源代碼的組成。token_get_all函 數參數為一段PHP代碼,可提取出這段代碼裡的常量、變量、類名、函數等。這在編寫phpdoc、代碼優化提速、自動加載類時都可以用到。比如,在解析 URL時沒必要用正規表達式,使用parse_url函數即可;在擷取HTTP頭時,也可以使用get_headers函數。

這裡總結幾種正規表達式的取代方案,他們能部分取代正規表達式的實作。

PHP的字元串函數;

PHP的Tokenizer系列函數;

PHP的url函數及一些http函數;

PHP的filter系列函數;

JavaScript的DOM模型。

以上内容,摘自《PHP核心技術與最佳實踐》——正規表達式相關章節,加深自己對正規表達式的了解與應用,在這裡分享給大家。

由 PHP樂知部落格 提供 http://tech.42xiu.com/php-regex.html

繼續閱讀