譯:Java 中的正則表達式性能概述


原文鏈接:https://www.baeldung.com/java-regex-performance

作者: baeldung

譯者:Darren Luo

1. 概述

在本快速教程中,我們將展示模式匹配引擎是如何工作的。我們還將介紹在 Java 中優化正則表達式的不同方式。

有關正則表達式的的使用介紹,請參閱此文

2. 模式匹配引擎

java.util.regex 包使用了一種叫做 Nondeterministic Finite Automaton(NFA)(不確定性有窮自動機)的模式匹配引擎。它被認為是不確定的是因為在對給定字符串嘗試匹配正則表達式時,輸入的每個字符可能針對正則表達式的不同部分進行多次檢查。

在后台,上面提到的引擎使用回溯。這種通用算法嘗試用盡所有可能性,知道它宣告失敗。考慮下面的示例可以更好的理解 NFA:

"tra(vel|ce|de)m" 

在輸入字符串“travel”時,該引擎首先會查找“tra”並立即找到它。

在這之后,它將從第四個字符開始嘗試匹配“vel”。這將匹配上,所以她將繼續並嘗試匹配”m“。

那將不能匹配,因此,它將回到第四個字符並搜索”ce“。這次將不再匹配,所以它將再次回到第四個位置並嘗試匹配”de“。這個字符串耶不能匹配,因此它將返回輸入字符串的第二個字符並嘗試搜索另一個“tra”。

最后一次失敗時,算法將返回失敗。

在上面的簡單例子里,在嘗試將輸入字符串和正則表達式匹配時,引擎必須多次回溯。因此,減少回溯次數時非常重要的。

3. 優化正則表達式的方法

3.1 避免重新編譯

Java 中的正則表達式被編譯為內部數據接口。這個編譯時一個耗時的過程。

我們每次調用 String.matches(String regex) 方法時,制定的正則表達式都會重新編譯。

if (input.matches(regexPattern)) { // do something } 

我們可以看到,每次進行條件求值時,正則表達式將被編譯。

要進行優化,只能首先編譯模式,然后創建一個 Matcher 來查找值中的匹配:

Pattern pattern = Pattern.compile(regexPattern);
for(String value : values) { Matcher matcher = pattern.matcher(value); if (matcher.matches()) { // do something } } 

上述優化的替代方案時使用相同的 Matcher 示例及其 reset() 方法:

Pattern pattern = Pattern.compile(regexPattern);
Matcher matcher = pattern.matcher(""); for(String value : values) { matcher.reset(value); if (matcher.matches()) { // do something } } 

由於 Matcher 不是線程安全的情況,我們必須謹慎使用這種變體。在多線程場景中可能存在危險。

總而言之,無論哪種情況,我們都保證在任何時間點都只有一個 Matcher 用例,可以用 reset 來重用它。對於這個例子,重復使用預編譯已經足夠了。

3.2. 使用替換(Alternation)

正如上一節我們測試的那樣,替換使用不當可能會對性能產生影響。最重要的是將選項放置最可能發生的前方,這樣能更快的匹配。

此外,我們必須提取提取他們之間的共同模式。下面兩個是不一樣的:

(travel | trade | trace) 

對比:

tra(vel | de | ce) 

后一個更快,因為 NFA 將嘗試匹配“tra”,如果沒找到它,則不會嘗試任何替代方案。

3.3. 捕獲分組(Group)

每次我們捕獲分組時,我們都會遭受一次小規模的懲罰。

如果我們需要在分組里捕獲文本,我們應該考慮使用非捕獲分組。請用“(?:M)”替代使用“(M)”。

總結

在這篇短文中,我們簡要回顧了 NFA 的工作原理。然后,我們通過與扁我們的模式並重用 Matcher 來探索如何優化我們正則表達式的性能。

最后,我們指出我們在使用替換和分組的一些注意事項。

和往常一樣,可以在 Github 上找到完整的源代碼。

 

http://www.spring4all.com/article/1479

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM