Needle:基於 DFA 的正規表示式庫,可編譯為 JVM 位元組碼

banq發表於2024-05-14


許多年前,Kragen抱怨 Java 正規表示式的實現和效能,並建議發出 JVM 位元組碼的實現可以表現更好。

今天,我釋出了Needle的 0.0.1 版本,這是一個將正規表示式編譯為 JVM 位元組碼的庫。它將每個正規表示式編譯為確定性有限自動機 (DFA),然後將其編譯為 Java 類。

  • 程式碼會分析 DFA 以提取有助於更高效匹配的資訊。
  • 它能檢測出所需的字首、字尾和前字尾,
  • 這些字首、字尾和前字尾可以使用 String.indexOf 找到,而第一個字元則可以在 while 迴圈中輕鬆測試(例如 [Ss])。
  • 這使得該類在 DFA 自動機中花費的時間更少,而在快速迴圈中花費的時間更多。

基準
Regex 的效能不適合簡明扼要的總結,而needle 的設計更是如此。例如,

  • 有一種最佳化會計算匹配的最小和最大長度,並在無法匹配時提前退出。在測試整個字串是否與 regex 匹配時,或者在足夠小的字串中搜尋時,這種效果就會顯現出來,
  • 但在查詢大字串中的匹配子串時,這種效果就不會顯現。

我已經編寫了許多基準測試,涵蓋了許多不同的情況,但需要編寫程式碼來重複報告和比較結果。與此同時,我包含了一個特定基準測試 ( SherlockBenchmark ) 的結果。


對於每個正規表示式,我們搜尋《福爾摩斯歷險記》的古騰堡計劃版本,找到該模式的所有匹配項。對於每個正規表示式,我們比較了 Java 標準庫 Needle 和brics 自動機庫,這是一個高效的 DFA 實現。

Needle 在這些模式上比 brics 慢,但仍然比標準庫快得多。這是因為Needle 自動機的核心迴圈比brics 自動機慢。

當我們有一個可用的子字串用於搜尋時,正規表示式的效能由搜尋該子字串的速度決定,而自動機的速度則不太重要。但當沒有子串時,brics 獲勝。

相關文章