正規表示式(程式碼java版) | IT人

文章推薦指數: 80 %
投票人數:10人

看了好些天的正規表示式,終於有時間來寫一篇關於它的部落格了。

也是因為前段時間做標籤處理的工作用到,用正則匹配標籤規則,少寫了不少程式碼。

Togglenavigation IT人 IT人 正規表示式(程式碼java版) 夢想家haima發表於 2020-09-27 Java 目錄元字元檢測工具普通字元字元類預定義字元類數量詞預設數量詞自定義量詞預定義量詞邊界識別符號正則組簡單應用複雜組序捕獲組 重新釋出於2020年09月27日,寫於2016年 看了好些天的正規表示式,終於有時間來寫一篇關於它的部落格了。

也是因為前段時間做標籤處理的工作用到,用正則匹配標籤規則,少寫了不少程式碼。

在有的地方使用正規表示式確實特別棒。

參考博文http://blog.csdn.net/yaerfeng/article/details/28855587,文中提到程式設計師的七種基本技能,確實各種語言,系統裡幾乎都有對正則的支援,雖說不用精通,但也要基本運用沒問題。

元字元 元字元標識在正規表示式中有特殊含義的字元,正是由它們,正規表示式才真正存在。

JAVA中支援的元字元列表有:([{\^-$|}])?*+. ():正則組中使用 []:字元類中表示一個字元 {}:數量範圍標識 \:預定義字元類中使用 ^$:邊界標識 -:字元類中表示某個範圍時使用,和"[]"配合使用 |:邏輯或 ?*+:預定義數量詞 ^:邏輯非 .:點號匹配除換行符的任意字元(這個地方任然有點疑問) 這裡要特別說明一個符號&,雖然&&在字元類中扮演著邏輯與運算,但卻不在元字元行列中 檢測工具 為了學習簡單,寫了一段測試程式碼做檢測用,當然你也可以使用網上的檢測工具,由於目前各個語言正則的引擎各有取捨,所以線上工具的檢測結果不一定和程式碼檢測結果相同(基本上沒太大出入),但用於理解正則,還是很有用的。

簡單案例:匹配5個連續的數字 正規表示式為[0-9]{5},先用開源中國的線上測試工具測試一下。

待匹配的字串為“自由12345飛翔” JAVA檢測程式碼如下 /** *檢測簡單方法 *@paramtarget//待查詢匹配的字串 *@paramregex//匹配規則的正規表示式 */ publicstaticvoidsimpletest(Stringtarget,Stringregex){ Patternp=Pattern.compile(regex);//java.util.regex.Pattern; Matchermatcher=p.matcher(target);//java.util.regex.Pattern; while(matcher.find()){ System.out.println(matcher.group(0)); } } simpletest("自由12345飛翔","[0-9]{5}"); //執行結果如下 12345 普通字元 所謂普通字元即為非元字元,上文中提到的元字元列表,即不是上面列表中的字元,就視為普通字元,普通字元為原樣匹配 案例1,普通字元 simpletest("自123由飛12333翔","123"); //執行結果如下 123 123 如上案例中,會去目標字串"自123由飛12333翔"中查詢123,由於123為普通字元,沒有特殊含義,此時原樣匹配,所以匹配到"自123由飛12333翔"中兩組123 案例2,元字元 simpletest("自[]由飛翔","["); //執行結果如下 直接報錯Exceptioninthread"main"java.util.regex.PatternSyntaxException:Unclosedcharacterclass 如果要讓元字元原樣匹配,則需要用\轉義元字元,JAVA中\\才表示普通字串的\,所以為\\[ simpletest("自[]由飛翔","\\["); //執行結果如下 [ 如上,通過轉義,匹配到“自[]由飛翔”中的元字元[ 而線上工具可以直接將字元讀入,所以不用\\,\[就表示匹配字元[,如下 案例3,普通字元& simpletest("自&&由飛翔","&&"); //執行結果如下 && simpletest("自&由&飛翔","&"); //執行結果如下 & & 案例3可以看出,雖然&&有特殊含義,但單獨用時,不用轉義,和普通字元完全相同 字元類 字元類(characterclass),這裡這個詞語是個專用名詞,在JAVAAPI中的Pattern類中我們可以看到字元類的一個列表。

一個[]中的規則叫一個字元類,一個字元類僅匹配一個字元(一個位置) [abc]a、b或c(簡單類) [^abc]任何字元,除了a、b或c(否定) [a-zA-Z]a到z或A到Z,兩頭的字母包括在內(範圍)數字範圍也能類似表示如[0-9]代表0到9中任意一個數字 [a-d[m-p]]a到d或m到p:[a-dm-p](並集)**等同於[a-d|[m-p]]等同與[[a-d]|[m-p]]** [a-z&&[def]]d、e或f(交集) [a-z&&[^bc]]a到z,除了b和c:[ad-z](減去)差集 [a-z&&[^m-p]]a到z,而非m到p:[a-lq-z](減去)差集 案例 simpletest("abcd","[abc]"); //執行結果如下 a b c simpletest("abcd","[^abc]"); //執行結果如下 d simpletest("abcd","[a-zA-Z]"); //執行結果如下 a b c simpletest("an","[a-d[m-p]]"); //執行結果如下 a n simpletest("abcd","[a-z&&[def]]"); //執行結果如下 d simpletest("abcd","[a-z&&[^bc]]"); //執行結果如下 a d simpletest("an","[a-z&&[^m-p]]"); //執行結果如下 a 現在我們清楚的看出來,一個字元類,也就是[]及中間內容代表一個範圍,表示匹配一個字元,中括號中包含這個字元可能出現的所有情況,由於檢測工具中使用了迴圈查詢匹配,所以輸出結果會查詢到多個字元列印出來 預定義字元類 預定義字元類,是正規表示式中代表一組字元的特殊表示,由\打頭,如下為JAVAAPI中Pattern類的預定義字元類列表 .:任何字元(與行結束符可能匹配也可能不匹配) \d:數字:[0-9] \D:非數字:[^0-9] \s:空白字元:[\t\n\x0B\f\r] \S:非空白字元:[^\s] \w:單詞字元:[a-zA-Z_0-9] \W:非單詞字元:[^\w] 案例 simpletest("自由12345飛翔","\\d{5}");//同理,\d在JAVA中需要轉義 //執行結果如下 12345 simpletest("自由12345飛翔","\\D+");//預定義數量詞稍後再說 //執行結果如下 自由 飛翔 simpletest("自由\t飛翔","\\s+"); //執行結果如下 ``//此處匹配到一個空格和一個製表符 simpletest("自由\t飛翔","\\S+"); //執行結果如下 自由 飛翔 simpletest("自由abc飛翔","\\w+"); //執行結果如下 abc simpletest("自由abc飛翔","\\W+"); //執行結果如下 自由 飛翔 數量詞 預設數量詞 正則匹配中字元都有要匹配的數量,如果沒有加數量詞,預設數量為1,匹配一個的意思 案例1 simpletest("自由12345飛翔","\\D"); //執行結果如下 自 由 飛 翔 simpletest("自由12345飛翔","\\D+"); //執行結果如下 自由 飛翔 如上案例中\\D代表匹配查詢非數字字元,預設數量詞為1,所以查詢到一個非數字字元後直接列印後,便進入下次查詢,結果如上第一段程式碼 如上案例中\\D+中引入+號預定義量詞,代表匹配大於等於1次的連續非數字字元,所以匹配到自由後進入下一次查詢 自定義量詞 使用者希望匹配幾次,就給定匹配次數,我這裡姑且叫它自定義量詞吧。

由大括號,上下限數量組成,上限數量可以缺少 {n}:恰好n個 {n,}:大於等於n個 {n,m}:大於等於n個,小於等於m個 注意:並沒有{,m}這種寫法 案例 simpletest("自由12345飛翔","\\d{2}"); //執行結果如下 12 simpletest("自由12345飛翔","\\d{2,}"); //執行結果如下 12345 simpletest("自由12345飛翔","\\d{2,4}"); //執行結果如下 1234 simpletest("自由12345飛翔","\\d{,7}"); //執行結果如下 報錯Exceptioninthread"main"java.util.regex.PatternSyntaxException:Illegalrepetitionnearindex1 從上面案例中我們已經看出,量詞只形容最近字元的數量,大括號中可以指定具體字元的具體數量或者範圍。

預定義量詞 預定義量詞是正則中用?,+,*三個符號表示特定意思的量詞 ?:一次或者零次 +:一次或者多次 *:零次或者零次以上 案例1 simpletest("自由12345飛翔","\\d?"); //執行結果如下 //空行 //空行 1 2 3 4 5 //空行 //空行 這裡要特別解釋一下兩個空行的產生,正則引擎去自由12345飛翔查詢\\d?時,逐個字元從左到右查詢,由於?表示一個或者零個,所以第一個字元匹配成功得到0個數字,也就是一個空字元,所以列印出來,而後面匹配到1個數字“1”列印出來,在匹配到1個數字“2”列印出來、、 案例2 simpletest("自由12345飛翔","\\d+"); //執行結果如下 12345 這裡匹配至少一個數字,直接匹配到5個數字“12345”輸出 案例3 simpletest("自由12345飛翔","\\d*"); //執行結果如下 //空行 //空行 12345 //空行 //空行 這裡出現空行的原因和案例1中相同,因為\d*代表0次或者0次以上 邊界識別符號 如下為JAVAAPI中Pattern類的邊界識別符號列表 ^:行的開頭 $:行的結尾 \b:單詞邊界 \B:非單詞邊界 \A:輸入的開頭 \G:上一個匹配的結尾 \Z:輸入的結尾,僅用於最後的結束符(如果有的話) \z:輸入的結尾 目前並沒完全弄明白所有邊界識別符號的用法,抱歉,僅演示幾個。

案例1 simpletest("自由12345飛翔","^\\d+"); simpletest("12345飛翔","^\\d+"); //執行結果如下 12345 ^\\d+查詢行開頭緊跟1次或多次數字,顯然自由12345飛翔匹配失敗,因為12345並非行首,而12345飛翔匹配成功得到12345 案例2 simpletest("自由12345飛翔","^\\d+$"); simpletest("12345飛翔","^\\d+$"); simpletest("自由12345","^\\d+$"); simpletest("12345","^\\d+$"); //執行結果如下 12345 當\\d+前面加上行首邊界,後面加上行尾邊界後,該正則只能匹配到一串純數字,且數量滿足+量詞 案列3 simpletest("自由12345飛翔","\\b\\d+"); //執行結果如下 //啥也沒有 simpletest("自由12345飛翔","\\b\\d+"); //執行結果如下 12345 simpletest("自由12345飛翔","\\d+\\b"); //執行結果如下 12345 simpletest("12345","\\d+\\b"); //執行結果如下 12345 simpletest("12345","\\b\\d+"); //執行結果如下 12345 從案例3中我們可以看出所謂的\b單詞邊界就是指空格或者行首行位(或許還有其他,反正匹配到一個連續的詞的結束或者開始位置) 案例4 simpletest("自由12345飛翔","\\B\\d+"); //執行結果如下 12345 simpletest("自由12345飛翔","\\B\\d+"); //執行結果如下 2345 \B為非單詞邊界,和\b恰好相反,但案例4中效果卻和案例3中不是相反,不能匹配到12345,因為前面有空格,但2345前面是1,是非單詞邊界,所以匹配成功 正則組 至此前面,基本上把正規表示式簡單運用講完,現在我們來引入一個詞正則組,正則組是用()把一組字元當做一個整體,可以通過方法將這個組匹配到的字元單獨取出,同樣可以通過下標引用之前匹配到的該組的字元 簡單應用 案例 @Test publicvoidgrouptest(){ Stringregex="\\d(\\d+)(\\D+)"; Stringtarget="520LiLing"; Patternp=Pattern.compile(regex); Matchermatcher=p.matcher(target); while(matcher.find()){ System.out.println(matcher.group(0)); System.out.println(matcher.group(1)); System.out.println(matcher.group(2)); System.out.println(matcher.group(3)); } } //執行結果如下 520LiLing 20 LiLing Exceptioninthread"main"java.lang.IndexOutOfBoundsException:Nogroup3 從簡單案例中可以看出()中匹配到的數字可以用matcher.group(1)方法取出,1代表第一組,案例中第一組為(\d+),第二組為(\D+),第三組沒找到,報錯。

而matcher.group(1)代表整個正規表示式匹配到的內容。

複雜組序 JAVAAPI中Pattern類中有關於正則組順序的介紹,當遇到複雜的正則組時,怎麼來確定組的序號。

((A)(B(C)))表示一個正規表示式,A,B,C分別代表隨意一個表示式 group(1):((A)(B(C))) group(2):(A) group(3):(B(C)) group(4):(C) 從上面的列表說明不難總結出一個規律,將正規表示式從左到右讀過來,依次遇到()中的左括號(依次編號,先遇到哪一組的左括號先編號 案例 @Test publicvoidgrouptest(){ Stringregex="((\\d)(\\d+(\\D+)))"; Stringtarget="520LiLing"; Patternp=Pattern.compile(regex); Matchermatcher=p.matcher(target); while(matcher.find()){ System.out.println(matcher.group(1)); System.out.println(matcher.group(2)); System.out.println(matcher.group(3)); System.out.println(matcher.group(4)); } } //執行結果如下 520LiLing 5 20LiLing LiLing 案例和上文說明完全一致,1組為((\\d)(\\d+(\\D+))),2組為(\\d),3組為(\\d+(\\D+)),4組為(\\D+) 捕獲組 前面已經講過關於正則組的編號,以及引用,但這樣的作用似乎還不夠強大。

捕獲組,就是將之前的正則組通過\組序號捕獲,如\1(任然需要轉義\\1),再次利用。

(解釋起來太費勁,看案例吧) @Test publicvoidgrouptest(){ Stringregex="(\\d+).+\\1"; Stringtarget="520Li320Ling"; Patternp=Pattern.compile(regex); Matchermatcher=p.matcher(target); while(matcher.find()){ System.out.println(matcher.group(0)); System.out.println(matcher.group(1)); } } //執行結果如下 20Li320 20 上面案例中,正規表示式(\\d+).+\\1的意思就是先查詢到數字標記為組1,然後跟著任意字元,跟著\\1表示捕獲和組1一模一樣的內容。

相關文章 Java泛型詳解 2020-11-22 Java 流程控制與陣列—Java基礎學習(二) 2020-11-22 Java Scala與Java差異(五)之Map與Tuple 2020-11-22 Java Java之定時任務全家桶 2020-11-22 Java [練手]CantoneseCool一個能說廣東話的小程式。

2020-11-22 靠這份面試手冊拿下京東的Java研發崗的offer,萬分感謝特此分享 2020-11-22 Java面試 leetcode【每日一題】242.有效的字母異位詞java 2020-11-22 JavaLeetCode HeadFirstJava學習筆記(7):繼承與多型 2020-11-22 Java 遊戲程式設計模式學習:第一章命令模式 2020-11-22 設計模式 Java學生管理系統(MVC)開源原始碼(基礎版) 2020-11-22 Java JavaScript正則學習筆記 2020-11-22 JavaScript 小白不懂就問,學自動化測試,會Java可以嗎,還是必須得會python(python不太會) 2020-11-22 PythonJava自動化測試 JavaBean重寫Object類中的方法 2020-11-22 Java Git程式碼託管常用命令 2020-11-22 Git 基於Java的Socket類Tcp網路程式設計實現實時聊天互動程式(一):QQ聊天介面的搭建 2020-11-22 Java java的序列化Serializable 2020-11-22 Java 實用小程式(1)之讀取xml並儲存為txt文字 2020-11-22 編寫程式實現f(n)=f(n-1)+f(n-2)(f(1)=1和f(2)=2)函式。

2020-11-22 最新文章 FlexJobs:遠端工作調查 TypeScriptlet與var的區別 Dubbo學習筆記(一)基本概念與簡單使用 React技巧之設定input值 程式語言:型別系統的本質 品質影音體驗,暢享娛樂生活丨HMSCore.Sparkle影音娛樂創新線上沙龍報名啟動 一套十萬級TPS的IM綜合訊息系統的架構實踐與思考 蘋果自研5G晶片或已失敗;騰訊QQ回應大規模賬號被盜;Vim9.0釋出|思否週刊 陳賢亭:跨境電商管理思維模型和實戰工具(附下載) 測試右移:線上質量監控ELK實戰 【前端面試】(特別篇)面試準備——相互瞭解階段 簡單聊聊運維監控的其他用途



請為這篇文章評分?