最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java正則表達式優(yōu)化超詳細舉例講解

 更新時間:2025年07月18日 11:08:26   作者:天狼1222  
正則表達式是一種強大的文本處理工具,在數(shù)據(jù)驗證、字符串搜索和替換等方面有廣泛應用,這篇文章主要介紹了java正則表達式優(yōu)化的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

1,什么是正則表達式

正則表達式使用一些特定的元字符來檢索、匹配以及替換符合規(guī)則的字符串。

構造正則表達式語法的元字符,由普通字符、標準字符、限定字符(量詞)、定位字符(邊界字符)組成

普通字符

字母[a-zA-Z]、數(shù)字[0-9]、下劃線[-]、漢字、標點符號等。比如,regex=[a-z]匹配從a到z,26個字母的任意一個。

標準字符

能夠與“多種普通字符”匹配的簡單表達式。比如,\d、\w、\s等,匹配數(shù)字0到9的任意數(shù)字可以用普通字符實現(xiàn)regex=[0-9],也可以用標準字符實現(xiàn)regex=\d。

限定字符(量詞)

用于表示匹配的字符數(shù)量。比如,*、+、?、[n}等,匹配任意1到3位的數(shù)字可以使用regex=\d{1,3}表示。

定位字符(邊界字符)

“零寬”,標記匹配符合某種條件的位置。比如,$、^等字符,匹配以Hello開頭的字符串可以使用regex=^Hello表示。

2. 正則表達式引擎

正則表達式是一個用正則符號寫出的公式,程序對這個公式進行語法分析,建立一個語法分析樹,再根據(jù)這個分析樹結合正則表達式的引擎生成執(zhí)行程序(這個執(zhí)行程序我們把它稱作狀態(tài)機,也叫狀態(tài)自動機),用于字符匹配。

而這里的正則表達式引擎就是一套核心算法,用于建立狀態(tài)機。

目前實現(xiàn)正則表達式引擎的方式有兩種:DFA 自動機(Deterministic Final Automata 確定有限狀態(tài)自動機)和 NFA 自動機(Non deterministic Finite Automaton 非確定有限狀態(tài)自動機)。

對比來看,構造 DFA 自動機的代價遠大于 NFA 自動機,但 DFA 自動機的執(zhí)行效率高于NFA 自動機。

假設一個字符串的長度是 n,如果用 DFA 自動機作為正則表達式引擎,則匹配的時間復雜度為 O(n);如果用 NFA 自動機作為正則表達式引擎,由于 NFA 自動機在匹配過程中存在大量的分支和回溯,假設 NFA 的狀態(tài)數(shù)為 s,則該匹配算法的時間復雜度為 O(ns)。

NFA 自動機的優(yōu)勢是支持更多功能。例如,捕獲 group、環(huán)視、占有優(yōu)先量詞等高級功能。這些功能都是基于子表達式獨立進行匹配,因此在編程語言里,使用的正則表達式庫都是基于 NFA 實現(xiàn)的。

那么 NFA 自動機到底是怎么進行匹配的呢?我以下面的字符和表達式來舉例說明。

text=“aabcab”

regex=“bc”

NFA 自動機會讀取正則表達式的每一個字符,拿去和目標字符串匹配,匹配成功就換正則表達式的下一個字符,反之就繼續(xù)和目標字符串的下一個字符進行匹配。

分解一下過程

首先,讀取正則表達式的第一個匹配符和字符串的第一個字符進行比較,b 對 a,不匹配;繼續(xù)換字符串的下一個字符,也是 a,不匹配;繼續(xù)換下一個,是 b,匹配。

然后,同理,讀取正則表達式的第二個匹配符和字符串的第四個字符進行比較,c 對 c,匹配;繼續(xù)讀取正則表達式的下一個字符,然而后面已經沒有可匹配的字符了,結束。

這就是 NFA 自動機的匹配過程,雖然在實際應用中,碰到的正則表達式都要比這復雜,但匹配方法是一樣的。   

NFA 自動機的回溯

用 NFA 自動機實現(xiàn)的比較復雜的正則表達式,在匹配過程中經常會引起回溯問題。大量的

回溯會長時間地占用 CPU,從而帶來系統(tǒng)性能開銷。我來舉例說明。

text=“abbc”

regex=“ab{1,3}c”

這個例子,匹配目的比較簡單。匹配以 a 開頭,以 c 結尾,中間有 1-3 個 b 字符的字符串。

NFA 自動機對其解析的過程是這樣的:

首先,讀取正則表達式第一個匹配符 a 和字符串第一個字符 a 進行比較,a 對 a,匹配。

然后,讀取正則表達式第二個匹配符 b{1,3} 和字符串的第二個字符 b 進行比較,匹配。但因為 b{1,3} 表示 1-3 個 b 字符串,NFA 自動機又具有貪婪特性,所以此時不會繼續(xù)讀取正則表達式的下一個匹配符,而是依舊使用 b{1,3} 和字符串的第三個字符 b 進行比較,結果還是匹配。

接著繼續(xù)使用 b{1,3} 和字符串的第四個字符 c 進行比較,發(fā)現(xiàn)不匹配了,此時就會發(fā)生回溯,已經讀取的字符串第四個字符 c 將被吐出去,指針回到第三個字符 b 的位置。

那么發(fā)生回溯以后,匹配過程怎么繼續(xù)呢?程序會讀取正則表達式的下一個匹配符 c,和字符串中的第四個字符 c 進行比較,結果匹配,結束。

如何避免回溯問題?

既然回溯會給系統(tǒng)帶來性能開銷,那如何應對呢?如果你有仔細看上面那個案例的話,

你會發(fā)現(xiàn) NFA 自動機的貪婪特性就是導火索,這和正則表達式的匹配模式息息相關.

1. 貪婪模式(Greedy)

顧名思義,就是在數(shù)量匹配中,如果單獨使用 +、 ? 、* 或{min,max} 等量詞,正則表達式會匹配盡可能多的內容。

例如,上邊那個例子:

text=“abbc”

regex=“ab{1,3}c”

就是在貪婪模式下,NFA 自動機讀取了最大的匹配范圍,即匹配 3 個 b 字符。匹配發(fā)生了一次失敗,就引起了一次回溯。如果匹配結果是“abbbc”,就會匹配成功。

2. 懶惰模式(Reluctant)

在該模式下,正則表達式會盡可能少地重復匹配字符。如果匹配成功,它會繼續(xù)匹配剩余的字符串。

例如,在上面例子的字符后面加一個“?”,就可以開啟懶惰模式。

text=“abc”

regex=“ab{1,3}?c”

匹配結果是“abc”,該模式下 NFA 自動機首先選擇最小的匹配范圍,即匹配 1 個 b 字符,因此就避免了回溯問題。

3. 獨占模式(Possessive)

同貪婪模式一樣,獨占模式一樣會最大限度地匹配更多內容;不同的是,在獨占模式下,匹配失敗就會結束匹配,不會發(fā)生回溯問題。

還是上邊的例子,在字符后面加一個“+”,就可以開啟獨占模式。

text=“abbc”

regex=“ab{1,3}+bc”

結果是不匹配,結束匹配,不會發(fā)生回溯問題。

避免回溯的方法就是:使用懶惰模式和獨占模式。

3,正則表達式的優(yōu)化

1. 少用貪婪模式,多用獨占模式

貪婪模式會引起回溯問題,我們可以使用獨占模式來避免回溯。

2. 減少分支選擇

分支選擇類型“(X|Y|Z)”的正則表達式會降低性能,我們在開發(fā)的時候要盡量減少使用。

如果一定要用,我們可以通過以下幾種方式來優(yōu)化:

首先,我們需要考慮選擇的順序,將比較常用的選擇項放在前面,使它們可以較快地被匹配;

其次,我們可以嘗試提取共用模式,例如,將“(abcd|abef)”替換為“ab(cd|ef)”,后者匹配速度較快,因為 NFA 自動機會嘗試匹配 ab,如果沒有找到,就不會再嘗試任何選項;

最后,如果是簡單的分支選擇類型,我們可以用三次 index 代替“(X|Y|Z)”,如果測試的話,你就會發(fā)現(xiàn)三次 index 的效率要比“(X|Y|Z)”高出一些。

3. 減少捕獲嵌套 (?:exp)

捕獲組是指把正則表達式中,子表達式匹配的內容保存到以數(shù)字編號或顯式命名的數(shù)組中,方便后面引用。一般一個 () 就是一個捕獲組,捕獲組可以進行嵌套。

非捕獲組則是指參與匹配卻不進行分組編號的捕獲組,其表達式一般由(?:exp)組成。

在正則表達式中,每個捕獲組都有一個編號,編號 0 代表整個匹配到的內容。

例子:

public static void main(String args[]) {
    String text = "<input high=\"20\" weight=\"70\">test</input>";
    String reg = "(<input.*?>)(.*?)(</input>)";
    Pattern p = Pattern.compile(reg);
    Matcher m = p.matcher(text);
    while (m.find()) {
        System.out.println(m.group(0));
        System.out.println(m.group(1));
        System.out.println(m.group(2));
        System.out.println(m.group(3));
    }
}

輸出:

<input high=\"20\" weight=\"70\">test</input>
<input high=\"20\" weight=\"70\">
test
</input>

如果你并不需要獲取某一個分組內的文本,那么就使用非捕獲分組。例如,使用“(?:X)”代替“(X)”

public static void main(String args[]) {
    String text = "<input high=\"20\" weight=\"70\">test</input>";
    String reg="(?:<input.*?>)(.*?)(?:</input>)";
    Pattern p = Pattern.compile(reg);
    Matcher m = p.matcher(text);
    while (m.find()) {
        System.out.println(m.group(0));
        System.out.println(m.group(1));
    }
}

輸出:

<input high=\"20\" weight=\"70\">test</input>
test

綜上:減少不需要獲取的分組,可以提高正則表達式的性能。

總結

正則表達式雖然小,卻有著強大的匹配功能。我們經常用到它,比如,注冊頁面手機號或郵箱的校驗。

但很多時候,我們又會因為它小而忽略它的使用規(guī)則,測試用例中又沒有覆蓋到一些特殊用例,導致上線就中招的情況發(fā)生。

如果要使用正則表達式,要在做好性能排查的前提下;如果不能,那么正則表達式能不用就不用,以此避免造成更多的性能問題。

如果要使用正則表達式,養(yǎng)成使用獨占或者懶惰模式的習慣。

到此這篇關于java正則表達式優(yōu)化的文章就介紹到這了,更多相關java正則表達式優(yōu)化內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • IntelliJ IDEA 2021.1 首個 Beta 版本發(fā)布

    IntelliJ IDEA 2021.1 首個 Beta 版本發(fā)布

    這篇文章主要介紹了IntelliJ IDEA 2021.1 首個 Beta 版本發(fā)布,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • Springboot2.0處理自定義異常并返回json

    Springboot2.0處理自定義異常并返回json

    這篇文章主要介紹了Springboot2.0處理自定義異常并返回json,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-11-11
  • java啟動jar包修改JVM默認內存問題

    java啟動jar包修改JVM默認內存問題

    這篇文章主要介紹了java啟動jar包修改JVM默認內存問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • 詳解SpringBoot如何統(tǒng)一處理返回的信息

    詳解SpringBoot如何統(tǒng)一處理返回的信息

    現(xiàn)在的項目是前后端開發(fā)的居多,那么我們怎么定義接口返回的數(shù)據(jù),怎么使用?Spring?Boot?來統(tǒng)一處理返回的信息呢,本文就來和大家簡單講講
    2023-06-06
  • java.lang.OutOfMemoryError 錯誤整理及解決辦法

    java.lang.OutOfMemoryError 錯誤整理及解決辦法

    這篇文章主要介紹了java.lang.OutOfMemoryError 錯誤整理及解決辦法的相關資料,需要的朋友可以參考下
    2016-10-10
  • Maven重復依賴問題解決(同一個jar多個版本)

    Maven重復依賴問題解決(同一個jar多個版本)

    本文主要介紹了Maven重復依賴問題解決(同一個jar多個版本),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-06-06
  • SpringBoot3集成Quartz的示例代碼

    SpringBoot3集成Quartz的示例代碼

    Quartz由Java編寫的功能豐富的開源作業(yè)調度框架,可以集成到幾乎任何Java應用程序中,并且能夠創(chuàng)建多個作業(yè)調度,在實際的業(yè)務中,有很多場景依賴定時任務,比如常見的:訂單超時處理,業(yè)務識別和預警通知等,本文介紹了SpringBoot3如何集成Quartz
    2023-08-08
  • Java 實現(xiàn)RSA非對稱加密算法

    Java 實現(xiàn)RSA非對稱加密算法

    RSA解決了對稱加密的一個不足,比如AES算法加密和解密時使用的是同一個秘鑰,因此這個秘鑰不能公開,因此對于需要公開秘鑰的場合,我們需要在加密和解密過程中使用不同的秘鑰,加密使用的公鑰可以公開,解密使用的私鑰要保密,這就是非對稱加密的好處?!?/div> 2021-06-06
  • 深入學習MyBatis中的參數(shù)(推薦)

    深入學習MyBatis中的參數(shù)(推薦)

    大家日常使用MyBatis經常會遇到一些異常,想要避免參數(shù)引起的錯誤,我們需要深入了解參數(shù)。想了解參數(shù),我們首先看MyBatis處理參數(shù)和使用參數(shù)的全部過程。下面這篇文章主要給大家介紹了MyBatis中參數(shù)的的相關資料,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-06-06
  • Java如何使用流去除集合中某個字段為空的對象

    Java如何使用流去除集合中某個字段為空的對象

    這篇文章主要給大家介紹了關于Java如何使用流去除集合中某個字段為空的對象,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Java具有一定的參考學習價值,需要的朋友可以參考下
    2023-08-08

最新評論

莎车县| 封丘县| 吉安市| 鄂温| 潍坊市| 永仁县| 如皋市| 信阳市| 梓潼县| 渭南市| 景洪市| 石棉县| 瑞昌市| 广丰县| 周宁县| 如东县| 富川| 新源县| 台安县| 红桥区| 象州县| 南康市| 汪清县| 苗栗市| 南靖县| 称多县| 平度市| 景泰县| 新泰市| 方正县| 内乡县| 宁河县| 枞阳县| 疏附县| 西青区| 荥阳市| 巴楚县| 阿城市| 衡阳县| 赤水市| 古浪县|