讀古今文學網 > 精通正則表達式(第3版) > 第6章 打造高效正則表達式 >

第6章 打造高效正則表達式

Crafting an Efficient Expression

Perl、Java、.NET、Python和PHP(這裡沒有列全,其他語言請參考第145頁的表格)使用的都是表達式主導的NFA引擎,細微的改變就可能對匹配的結果及方式產生重大的影響。DFA中不存在的問題,對NFA來說卻很重要。因為NFA引擎容許用戶進行精確控制,所以我們可以用心打造(譯注1)正則表達式,但對不熟悉的人來說,這樣可能會帶來麻煩。本章講解的就是調校正則表達式的訣竅。

調校表達式時需要考慮的兩個因素是準確性和效率:精確匹配我們需要的文本,不包含多餘的內容,而且速度要快。第4章和第5章探討了準確性,現在我們來考察NFA引擎的效率,以及如何有效地利用這些知識(我們會在合適的時候提到DFA的問題,不過本章主要關注的還是基於 NFA 的引擎)。總的來說,關鍵在於徹底理解回溯背後的過程,學習些技巧來避免可能的回溯。在深入瞭解了處理機制的細節之後,讀者不但能夠把匹配的速度提到最高,寫更複雜的正則表達式時也會更有信心。

本章內容

為了讓讀者徹底掌握這些知識,本章首先說明了效率的重要性,然後回顧前幾章講解過的回溯,重點強調效率和回溯對整個匹配的影響,為掌握高級的技巧做準備。然後我們會考察一些常見的內部優化措施,它們可能對效率有相當程度的實質性影響;還要講解,針對具體實現方式,如何構建最合適的正則表達式。最後,我會做個總結,傳授一些終極技巧,來構建快如雷霆的NFA表達式。

測試與回溯

我們將看到的例子代表了使用正則表達式時經常遇到的情況。在分析某個的正則表達式的效率時,我有時會列出正則引擎在匹配過程中進行的獨立測試(inpidual test)的次數。如果用正則表達式「marty」匹配smarty,一共會進行6次獨立測試,首先是「m」對s(匹配失敗),然後是「m」對m,「a」對a,依次繼續。我通常會給出回溯的次數(本例中回溯次數為0,不過,正則引擎的傳動裝置必然會在第二個字符處重試正則表達式,這或許可以算作一次回溯)

之所以要列出這些數字,並不是為表明精確性,而是因為它們比「許多」、「少量」、「多次」、「更好」、「不太多」之類更為準確。我的意思不是說,在NFA上使用正則表達式需要精確地考察測試和回溯的次數,我只是希望讓讀者知道這些例子的相對優劣。

另一個重要的問題是,你必須意識到這些「精確」的數字可能根據工具的不同而有所不同。我期望讀者能夠知道,它只是針對具體例子的、相對的粗略表現。不同工具之間的一個重要區別就是,它們可能使用的優化措施不同。如果能夠預先判斷目標字符串基本無法匹配(例如目標字符串缺少一個引擎能夠預知的,匹配成功必須的字符),足夠聰明的實現方式可以完全不應用正則表達式。我在本章討論了這些重要的優化措施,不過普遍原理比具體問題更為重要。

傳統型NFA還是POSIX NFA

在分析效率時,一定不要忘記所使用工具的引擎類型:傳統型NFA還是POSIX NFA。下一節中我們會看到,有些問題只對某種引擎存在。有的改變可能對其中之一沒有影響,對另一個卻有極大的影響。還是那句話,理解基本原理,就能應付各種情況。