?正則表達式一般用于字符串匹配, 字符串查找和字符串替換. 別小看它的作用, 在工作學習中靈活運用正則表達式處理字符串能夠大幅度提高效率, 編程的快樂來得就是這么簡單.
?一下子給出一堆匹配的規則可能會讓人恐懼, 下面將由淺入深講解正則表達式的使用.
?先上代碼
publicclassDemo1{publicstaticvoidmain(String[]args){//字符串abc匹配正則表達式"...",其中"."表示一個字符//"..."表示三個字符System.out.println("abc".matches("..."));System.out.println("abcd".matches("..."));}}//輸出結果truefalse
?String類中有個matches(String regex)
方法, 返回值為布爾類型, 用于告訴這個字符串是否匹配給定的正則表達式.
?在本例中我們給出的正則表達式為..., 其中每個.表示一個字符, 整個正則表達式的意思是三個字符, 顯然當匹配abc的時候結果為true, 匹配abcd時結果為false.
?在java.util.regex包下有兩個用于正則表達式的類, 一個是Matcher類, 另一個Pattern. Java官方文檔中給出對這兩個類的典型用法, 代碼如下:
publicclassDemo1{publicstaticvoidmain(String[]args){//字符串abc匹配正則表達式"...",其中"."表示一個字符//"..."表示三個字符System.out.println("abc".matches("..."));System.out.println("abcd".matches("..."));}}//輸出結果truefalse
?如果要深究正則表達式背后的原理, 會涉及編譯原理中自動機等知識, 此處不展開描述. 為了達到通俗易懂, 這里用較為形象的語言描述.
?Pattern可以理解為一個模式, 字符串需要與某種模式進行匹配. 比如Demo2中, 我們定義的模式是一個長度為3的字符串, 其中每個字符必須是a~z中的一個.
?我們看到創建Pattern對象時調用的是Pattern類中的compile方法, 也就是說對我們傳入的正則表達式編譯后得到一個模式對象. 而這個經過編譯后模式對象, 會使得正則表達式使用效率會大大提高, 并且作為一個常量, 它可以安全地供多個線程并發使用.
?Matcher可以理解為模式匹配某個字符串后產生的結果. 字符串和某個模式匹配后可能會產生很多個結果, 這個會在后面的例子中講解.
?最后當我們調用m.matches()時就會返回完整字符串與模式匹配的結果
?上面的三行代碼可以簡化為一行代碼System.out.println("abc".matches("[a-z]{3}"));
?但是如果一個正則表達式需要被重復匹配, 這種寫法效率較低.
?在介紹之前首先要說明的是, 正則表達式的具體含義不用強背, 各個符號的含義在Java官方文檔的Pattern類描述中或網上有詳細的定義. 當然能熟用就更好了.
publicclassDemo3{/***為了省略每次寫打印語句,這里把輸出語句封裝起來*@paramo*/privatestaticvoidp(Objecto){System.out.println(o);}/***.Anycharacter(mayormaynotmatchlineterminators),任意字符*X?X,onceornotatall零個或一個*X*X,zeroormoretimes零個或多個*X+X,oneormoretimes一個或多個*X{n}X,exactlyntimesx出現n次*X{n,}X,atleastntimesx出現至少n次*X{n,m}X,atleastnbutnotmorethanmtimes出現n~m次*@paramargs*/publicstaticvoidmain(String[]args){p("a".matches("."));p("aa".matches("aa"));p("aaaa".matches("a*"));p("aaaa".matches("a+"));p("".matches("a*"));p("a".matches("a?"));//\dAdigit:[0-9],表示數字,但是在java中對"\"這個符號需要使用\進行轉義,所以出現\\dp("2345".matches("\\d{2,5}"));//\\.用于匹配"."p("192.168.0.123".matches("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"));//[0-2]指必須是0~2中的一個數字p("192".matches("[0-2][0-9][0-9]"));}}//輸出結果//全為true
?[]用于描述一個字符的范圍, 下面是一些例子
publicclassDemo4{privatestaticvoidp(Objecto){System.out.println(o);}publicstaticvoidmain(String[]args){//[abc]指abc中的其中一個字母p("a".matches("[abc]"));//[^abc]指除了abc之外的字符p("1".matches("[^abc]"));//a~z或A~Z的字符,以下三個均是或的寫法p("A".matches("[a-zA-Z]"));p("A".matches("[a-z|A-Z]"));p("A".matches("[a-z[A-Z]]"));//[A-Z&&[REQ]]指A~Z中并且屬于REQ其中之一的字符p("R".matches("[A-Z&&[REQ]]"));}}//輸出結果
認識\s \w \d - 下面介紹數字和字母的正則表達, 這是編程中使用最多的字符了.
關于\
?這里重點介紹最不好理解的\. 在Java中的字符串中, 如果要用到特殊字符, 必須通過在前面加\進行轉義.
?舉個例子, 考慮這個字符串"老師大聲說:"同學們,快交作業!"". 如果我們沒有轉義字符, 那么開頭的雙引號的結束應該在說:"這里, 但是我們的字符串中需要用到雙引號, 所以需要用轉義字符
?使用轉義字符后的字符串為"老師大聲說:\"同學們,快交作業!\"", 這樣我們的原意才能被正確識別.
?同理如果我們要在字符串中使用\, 也應該在前面加一個\, 所以在字符串中表示為"\\"
?那么如何在正則表達式中表示要匹配\呢, 答案為"\\\\".
?我們分開考慮: 由于正則式中表示\同樣需要轉義, 所以前面的\\表示正則表達式中的轉義字符\, 后面的\\表示正則表達式中\本身, 合起來在正則表達式中表示\.
?如果感覺有點繞的話請看下面代碼
publicclassDemo5{privatestaticvoidp(Objecto){System.out.println(o);}publicstaticvoidmain(String[]args){/***\dAdigit:[0-9]數字*\DAnon-digit:[^0-9]非數字*\sAwhitespacecharacter:[\t\n\x0B\f\r]空格*\SAnon-whitespacecharacter:[^\s]非空格*\wAwordcharacter:[a-zA-Z_0-9]數字字母和下劃線*\WAnon-wordcharacter:[^\w]非數字字母和下劃線*///\\s{4}表示4個空白符p("\n\r\t".matches("\\s{4}"));//\\S表示非空白符p("a".matches("\\S"));//\\w{3}表示數字字母和下劃線p("a_8".matches("\\w{3}"));p("abc888&^%".matches("[a-z]{1,3}\\d+[%^&*]+"));//匹配\p("\\".matches("\\\\"));}}//輸出結果
邊界處理
?^在中括號內表示取反的意思[^], 如果不在中括號里則表示字符串的開頭.
publicclassDemo6{privatestaticvoidp(Objecto){System.out.println(o);}publicstaticvoidmain(String[]args){/***^Thebeginningofaline一個字符串的開始*$Theendofaline字符串的結束*\bAwordboundary一個單詞的邊界,可以是空格,換行符等*/p("hellosir".matches("^h.*"));p("hellosir".matches(".*r$"));p("hellosir".matches("^h[a-z]{1,3}o\\b.*"));p("hellosir".matches("^h[a-z]{1,3}o\\b.*"));}}
?拿到一篇文章, 如何判斷里面有多少個空白行? 用正則表達式能方便地進行匹配, 注意空白行中可能包括空格, 制表符等.
p(" \n".matches("^[\\s&&[^\n]]*\\n$"));
?解釋: ^[\\s&&[^\n]]*是空格符號但不是換行符, \\n$最后以換行符結束
?下面是匹配郵箱
p("liuyj24@126.com".matches("[\\w[.-]]+@[\\w[.-]]+\\.[\\w]+"));
?解釋: [\\w[.-]]+以一個或多個數字字母下劃線.或-組成, @接著是個@符號, 然后同樣是[\\w[.-]]+, 接著\\.匹配., 最后同樣是[\\w]+
Matcher類的matches(),find()和lookingAt()
?matches()方法會將整個字符串與模板進行匹配.
?find()則是從當前位置開始進行匹配, 如果傳入字符串后首先進行find(), 那么當前位置就是字符串的開頭, 對當前位置的具體分析可以看下面的代碼示例
?lookingAt()方法會從字符串的開頭進行匹配.
publicclassDemo8{privatestaticvoidp(Objecto){System.out.println(o);}publicstaticvoidmain(String[]args){Patternpattern=pattern.compile("\\d{3,5}");Strings="123-34345-234-00";Matcherm=pattern.matcher(s);//先演示matches(),與整個字符串匹配.p(m.matches());//結果為false,顯然要匹配3~5個數字會在-處匹配失敗//然后演示find(),先使用reset()方法把當前位置設置為字符串的開頭m.reset();p(m.find());//true匹配123成功p(m.find());//true匹配34345成功p(m.find());//true匹配234成功p(m.find());//false匹配00失敗//下面我們演示不在matches()使用reset(),看看當前位置的變化m.reset();//先重置p(m.matches());//false匹配整個字符串失敗,當前位置來到-p(m.find());//true匹配34345成功p(m.find());//true匹配234成功p(m.find());//false匹配00始邊p(m.find());//false沒有東西匹配,失敗//演示lookingAt(),從頭開始找p(m.lookingAt());//true找到123,成功}}
?如果一次匹配成功的話start()用于返回匹配開始的位置, end()用于返回匹配結束字符的后面一個位置
publicclassDemo9{privatestaticvoidp(Objecto){System.out.println(o);}publicstaticvoidmain(String[]args){Patternpattern=Pattern.compile("\\d{3,5}");Strings="123-34345-234-00";Matcherm=pattern.matcher(s);p(m.find());//true匹配123成功p("start:"+m.start()+"-end:"+m.end());p(m.find());//true匹配34345成功p("start:"+m.start()+"-end:"+m.end());p(m.find());//true匹配234成功p("start:"+m.start()+"-end:"+m.end());p(m.find());//false匹配00失敗try{p("start:"+m.start()+"-end:"+m.end());}catch(Exceptione){System.out.println("報錯了...");}p(m.lookingAt());p("start:"+m.start()+"-end:"+m.end());}}//輸出結果truestart:0-end:3truestart:4-end:9truestart:10-end:13false報錯了...truestart:0-end:3
替換字符串
?想要替換字符串首先要找到被替換的字符串, 這里要新介紹Matcher類中的一個方法group(), 它能返回匹配到的字符串.
?下面我們看一個例子, 把字符串中的java轉換為大寫.
publicclassDemo10{privatestaticvoidp(Objecto){System.out.println(o);}publicstaticvoidmain(String[]args){Patternp=Pattern.compile("java");Matcherm=p.matcher("javaJavaJAVAJAvaIloveJavaandyou");p(m.replaceAll("JAVA"));//replaceAll()方法會替換所有匹配到的字符串}}//輸出結果JAVAJavaJAVAJAvaIloveJavaandyou
升級: 不區分大小寫查找并替換字符串
?為了在匹配的時候不區分大小寫,我們要在創建模板模板時指定大小寫不敏感publicstaticvoidmain(String[]args){Patternp=Pattern.compile("java",Pattern.CASE_INSENSITIVE);//指定為大小寫不敏感的Matcherm=p.matcher("javaJavaJAVAJAvaIloveJavaandyou");p(m.replaceAll("JAVA"));}//輸出結果JAVAJAVAJAVAJAVAIloveJAVAandyou
?這里演示把查找到第奇數個字符串轉換為大寫, 第偶數個轉換為小寫
?這里會引入Matcher類中一個強大的方法appendReplacement(StringBuffer sb, String replacement), 它需要傳入一個
StringBuffer進行字符串拼接.
publicstaticvoidmain(String[]args){Patternp=Pattern.compile("java",Pattern.CASE_INSENSITIVE);Matcherm=p.matcher("javaJavaJAVAJAvaIloveJavaandyou?");StringBuffersb=newStringBuffer();intindex=1;while(m.find()){//m.appendReplacement(sb,(index++&1)==0?"java":"JAVA");較為簡潔的寫法if((index&1)==0){//偶數m.appendReplacement(sb,"java");}else{m.appendReplacement(sb,"JAVA");}index++;}m.appendTail(sb);//把剩余的字符串加入p(sb);}//輸出結果JAVAjavaJAVAjavaIloveJAVAandyou?
?先從一個問題引入, 看下面這段代碼
publicstaticvoidmain(String[]args){Patternp=Pattern.compile("\\d{3,5}[a-z]{2}");Strings="123aa-5423zx-642oi-00";Matcherm=p.matcher(s);while(m.find()){p(m.group());}}//輸出結果123aa5423zx642oi
?其中正則表達式"\\d{3,5}[a-z]{2}"表示3~5個數字跟上兩個字母, 然后打印出每個匹配到的字符串.
?如果想要打印每個匹配串中的數字, 如何操作呢.
?首先你可能想到把匹配到的字符串再進行匹配, 但是這樣太麻煩了, 分組機制可以幫助我們在正則表達式中進行分組.
?規定使用()進行分組, 這里我們把字母和數字各分為一組"(\\d{3,5})([a-z]{2})"
?然后在調用m.group(int group)方法時傳入組號即可
?注意, 組號從0開始, 0組代表整個正則表達式, 從0之后, 就是在正則表達式中從左到右每一個左括號對應一個組. 在這個表達式中第1組是數字, 第2組是字母.
publicstaticvoidmain(String[]args){Patternp=Pattern.compile("(\\d{3,5})([a-z]{2})");//正則表達式為3~5個數字跟上兩個字母Strings="123aa-5423zx-642oi-00";Matcherm=p.matcher(s);while(m.find()){p(m.group(1));}}//輸出結果1235423642
?假設我們手頭上有一些優質的資源, 打算分享給網友, 于是便到貼吧上發出一個留郵箱發資源的帖子. 沒想到網友熱情高漲, 留下了近百個郵箱. 但逐個復制發送太累了, 我們考慮用程序實現.
?這里不展開講發郵件部分, 重點應用已經學到的正則表達式從網頁中截取所有的郵箱地址.
?首先獲取一個帖子的html代碼隨便找了一個, 點擊跳轉, 在瀏覽器中點擊右鍵保存html文件
?接下來看代碼:
publicclassDemo12{publicstaticvoidmain(String[]args){BufferedReaderbr=null;try{br=newBufferedReader(newFileReader("C:\\emailTest.html"));Stringline="";while((line=br.readLine())!=null){//讀取文件的每一行parse(line);//解析其中的email地址}}catch(FileNotFoundExceptione){e.printStackTrace();}catch(IOExceptione){e.printStackTrace();}finally{if(br!=null){try{br.close();br=null;}catch(IOExceptione){e.printStackTrace();}}}}privatestaticvoidparse(Stringline){Patternp=Pattern.compile("[\\w[.-]]+@[\\w[.-]]+\\.[\\w]+");Matcherm=p.matcher(line);while(m.find()){System.out.println(m.group());}}}//輸出結果2819531636@qq.com2819531636@qq.com2405059759@qq.com2405059759@qq.com1013376804@qq.com...
?最后的一個實戰案例: 統計一個項目中一共有多少行代碼, 多少行注釋, 多少個空白行. 不妨對自己做過的項目進行統計, 發現不知不覺中也是個寫過成千上萬行代碼的人了...
?我在github上挑選了一個項目, 是純java寫的小項目, 方便統計. 點擊跳轉
?下面是具體的代碼, 除了判斷空行用了正則表達式外, 判斷代碼行和注釋行用了String類的api
publicclassDemo13{privatestaticlongcodeLines=0;privatestaticlongcommentLines=0;privatestaticlongwhiteLines=0;privatestaticStringfilePath="C:\\TankOnline";publicstaticvoidmain(String[]args){process(filePath);System.out.println("codeLines:"+codeLines);System.out.println("commentLines:"+commentLines);System.out.println("whiteLines:"+whiteLines);}/***遞歸查找文件*@parampathStr*/publicstaticvoidprocess(StringpathStr){Filefile=newFile(pathStr);if(file.isDirectory()){//是文件夾則遞歸查找File[]fileList=file.listFiles();for(Filef:fileList){StringfPath=f.getAbsolutePath();process(fPath);}}elseif(file.isFile()){//是文件則判斷是否是.java文件if(file.getName().matches(".*\\.java$")){parse(file);}}}privatestaticvoidparse(Filefile){BufferedReaderbr=null;try{br=newBufferedReader(newFileReader(file));Stringline="";while((line=br.readLine())!=null){line=line.trim();//清空每行首尾的空格if(line.matches("^[\\s&&[^\\n]]*$")){//注意不是以\n結尾,因為在br.readLine()會去掉\nwhiteLines++;}elseif(line.startsWith("/*")||line.startsWith("*")||line.endsWith("*/")){commentLines++;}elseif(line.startsWith("//")||line.contains("//")){commentLines++;}else{if(line.startsWith("import")||line.startsWith("package")){//導包不算continue;}codeLines++;}}}catch(FileNotFoundExceptione){e.printStackTrace();}catch(IOExceptione){e.printStackTrace();}finally{if(null!=br){try{br.close();br=null;}catch(IOExceptione){e.printStackTrace();}}}}}//輸出結果codeLines:1139commentLines:124whiteLines:172
?經過兩個實戰后, 相信大家已經掌握了正則表達式的基本使用了, 下面介紹貪婪模式與非貪婪模式. 通過查看官方api我們發現Pattern類中有如下定義:
X? X, once or not at all
X* X, zero or more times
X+ X, one or more times
X{n} X, exactly n times
X{n,} X, at least n times
X{n,m} X, at least n but not more than m times
X?? X, once or not at all
X*? X, zero or more times
X+? X, one or more times
X{n}? X, exactly n times
X{n,}? X, at least n times
X{n,m}? X, at least n but not more than m times
X?+ X, once or not at all
X*+ X, zero or more times
X++ X, one or more times
X{n}+ X, exactly n times
X{n,}+ X, at least n times
X{n,m}+ X, at least n but not more than m times
?這三種模式表達的意思是一樣的, 在前面的講解中我們全部使用的是貪婪模式. 那么其他兩種模式的寫法有什么區別呢? 通過下面的代碼示例進行講解.
publicstaticvoidmain(String[]args){Patternp=Pattern.compile(".{3,10}[0-9]");Strings="aaaa5bbbb6";//10個字符Matcherm=p.matcher(s);if(m.find()){System.out.println(m.start()+"-"+m.end());}else{System.out.println("notmatch!");}}//輸出結果0-10
?正則表達式的意思是3~10個字符加一個數字. 在貪婪模式下匹配時, 系統會先吞掉10個字符, 這時檢查最后一個是否時數字, 發現已經沒有字符了, 于是吐出來一個字符, 再次匹配數字, 匹配成功, 得到0-10.
?下面是非貪婪模式演示(勉強的, 不情愿的)
publicstaticvoidmain(String[]args){Patternp=Pattern.compile(".{3,10}?[0-9]");//添加了一個?Strings="aaaa5bbbb6";Matcherm=p.matcher(s);if(m.find()){System.out.println(m.start()+"-"+m.end());}else{System.out.println("notmatch!");}}//輸出結果0-5
?在非貪婪模式下, 首先只會吞掉3個(最少3個), 然后判斷后面一個是否是數字, 結果不是, 在往后吞一個字符, 繼續判斷后面的是否數字, 結果是, 輸出0-5
?最后演示獨占模式, 通常只在追求效率的情況下這么做, 用得比較少
publicstaticvoidmain(String[]args){Patternp=Pattern.compile(".{3,10}+[0-9]");//多了個+Strings="aaaa5bbbb6";Matcherm=p.matcher(s);if(m.find()){System.out.println(m.start()+"-"+m.end());}else{System.out.println("notmatch!");}}//輸出結果notmatch!
?獨占模式會一下吞進10個字符, 然后判斷后一個是否是數字, 不管是否匹配成功它都不會繼續吞或者吐出一個字符.
以上就是正則表達式在Java中如何使用,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注本站行業資訊頻道。
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
c語言中正確的字符常量是用一對單引號將一個字符括起表示合法的字符常量。例如‘a’。數值包括整型、浮點型。整型可用十進制,八進制,十六進制。八進制前面要加0,后面...
2022年天津專場考試原定于3月19日舉行,受疫情影響確定延期,但目前延期后的考試時間推遲。 符合報名條件的考生,須在規定時間登錄招考資訊網(www.zha...
:喜歡聽,樂意看。指很受歡迎?!巴卣官Y料”喜聞樂見:[ xǐ wén lè jiàn ]詳細解釋1. 【解釋】:喜歡聽,樂意看。指很受歡迎。2. 【示例】:這是...
(資料圖)最近這段時間總有小伙伴問小編羥基酪醇的作用是什么,小編為此在網上搜尋了一些有關于羥基酪醇的作用的知識送給大家,希望能解答各位小伙伴的疑惑。1、能有效增強皮膚彈性和潤澤,具除皺抗衰老之功效。2、有助于人體對礦物質的吸收,保持骨密度,減少骨骼疏松,同時提高內分泌系統功能,促進新陳代謝,促進傷口愈合,消除體內自由基,恢復人體臟腑器官的健康狀態,防止腦衰。3、可以防治肺癌,乳腺癌,子宮癌,前列腺...
最近這段時間總有小伙伴問小編找本女主是NPC的網游小說是什么,小編為此在網上搜尋了一些有關于找本女主是NPC的網游小說的知識送給大家,希望能解答各位小伙伴的疑惑。1、《網游之夢幻現實》作者:云天空;2、《娶個NPC夫人》作者:黃花梨;【資料圖】3、《菜鳥老公》作者:末尚尚;4、《網游之丑娘》作者:小小魚水中游;5、《千里佳期我來赴》作者:舒嘉妍;6、《全服第二》作者:落日薔薇;7、《網游之冬至秋離...
(相關資料圖)關于v幣是什么的知識大家了解嗎?以下就是小編整理的關于v幣是什么的介紹,希望可以給到大家一些參考,一起來了解下吧!V幣是統一電話支付工具和互聯網產品(服務)分銷渠道之一,于2003年由深圳市盈華訊方通信技術有限公司聯合中國電信、中國網通共同發起。V幣由15位號碼加6位密碼組成。用戶通過電話、手機、寬帶、電信充值卡等渠道購買到V幣,再憑V幣到上千家網站、網游、互聯網服務提供商進行充值,...