java正則表達式詳解

正則表達式:

正則表達式定義了字符串的模式。

正則表達式可以用來搜索、編輯或處理文本。

正則表達式並不僅限於某一種語言,但是在每種語言中有細微的差別。

Java 正則表達式和 Perl的是最爲相似的。

java.util.regex包主要包括以下三個類:

·        Pattern類:

pattern 對象是一個正則表達式的編譯表示。Pattern類沒有公共構造方法。要創建一個 Pattern對象,你必須首先調用其公共靜態編譯方法,它返回一個 Pattern對象。該方法接受一個正則表達式作爲它的第一個參數。

·        Matcher類:

Matcher 對象是對輸入字符串進行解釋和匹配操作的引擎。與Pattern類一樣,Matcher也沒有公共構造方法。你需要調用 Pattern對象的 matcher方法來獲得一個 Matcher對象。

·        PatternSyntaxException

PatternSyntaxException 是一個非強制異常類,它表示一個正則表達式模式中的語法錯誤。

 

         定義一個比較規則,用該規則去匹配想要匹配的東西,返回結果。

創建方式:


 

//創建正則對象
                   //調用靜態方法compile方法,傳參正則語句
                   String regex = "abcd";
                   String text = "++abcdabcd++";
                   Pattern pattern = Pattern.compile(regex);
                   //matcher匹配器對象
                    Matcher matcher = pattern.matcher(text);

進行匹配功能方法:find()查找,group()返回本次查找到的內容


注意,當find查找返回false時,再去執行group方法,就不會返回String,而是直接報錯,所以我們應該在執行group方法的時候進行一次判斷。

 

	 //進行匹配操作,返回匹配結果
                   //第一次默認從頭開始查找
                   boolean bool= matcher.find();
                   System.out.println(bool? "匹配成功" : "匹配失敗");
                   //查看匹配到的文本
                   String result = matcher.group();
                   System.out.println(result);
                   //第二次從上一次查找位置開始查找
                   bool=matcher.find();
                   System.out.println(bool? "匹配成功" : "匹配失敗");
                   //獲取匹配到的文本
                    result = matcher.group();
                   System.out.println(result);
                   //第三次從上一次查找位置開始查找
                   bool=matcher.find();
                   System.out.println(bool? "匹配成功" : "匹配失敗");
                   //獲取匹配到的文本,發現本次find查找失敗,查看group返回結果,報錯
                    //result = matcher.group();
                    //System.out.println(result);
                   //改造一下,我們在執行該方法時,進行一次if判斷
                   if(bool){
                            result= matcher.group();
                            System.out.println(result);
			}

到目前爲止,以上代碼已經是查找到了末尾,如果我想再次從指定位置查找,可以執行find(int index)方法,從指定位置進行查找,則又能查找成功。

               

	   	//從指定位置開始查找          
                   bool=matcher.find(0);
                   //匹配成功
                   System.out.println("從指定位置開始匹配"+ (bool ? "匹配成功" : "匹配失敗"));
                   result= matcher.group();
                   System.out.println(result);

start()和end()方法

start():返回匹配到文本第一位所在的索引

end():返回匹配到的文本末尾之後一位的索引

   

         //執行匹配方法
		   bool=matcher.find();
                   System.out.println("從指定位置開始匹配"+ (bool ? "匹配成功" : "匹配失敗"));
                   result= matcher.group();
                   System.out.println(result);
                   //查看一下匹配到文本內容的開始位置
                   start= matcher.start();
                   System.out.println("匹配到的開始位置:"+ start);
                   //查看一下匹配到的文本的結束位置後一位
                   end= matcher.end();
                   System.out.println("匹配到的結尾位置:"+ end);
		LookingAt()方法:從被匹配文本開始進行匹配,如果開始不滿足正則表達式,則返回false,滿足返回true。
                   //從開始位置進行匹配:lookingAt()
                   regex= "abcd";
                   text= "sdasdfasdfasfdaabcdefg";
                   pattern= Pattern.compile(regex);
                   matcher= pattern.matcher(text);
                   bool= matcher.lookingAt();
                   //返回失敗,因爲text開頭並不是abcd
                   System.out.println("從開始進行匹配"+ (bool ? "匹配成功" : "匹配失敗"));     

        

全匹配模式matcher()對整個匹配的文本進行匹配,返回布爾值:

		//正則表達式匹配整個字符串
                   text= "abcd";
                   matcher= pattern.matcher(text);
                   bool= matcher.matches();
                   System.out.println("全匹配" +(bool ? "匹配成功" : "匹配失敗"));     
                   //返回創建匹配器對象的pattern對象
                   Pattern pattern2 = matcher.pattern();
                   //比較返回的pattern2是否與創建mathcer對象的pattern一致
                   System.out.println((pattern== pattern2)?"與創建本matcher的對象是同一個對象":"其他對象");//true  


 

替換第一個匹配到的內容replaceFirst:

          

    	 	    //替換第一個匹配到的文本replaceFirst
                   regex= "abcd";
                   text= "sabcdabcdg";
                   pattern= Pattern.compile(regex);
                   matcher= pattern.matcher(text);
                   String rfResult = matcher.replaceFirst("替換的文本");
                   System.out.println("替換後的文本:"+rfResult);

Reset()重置匹配器matcher對象後,再次執行後,從開始進行匹配

           

	//重置匹配器,返回本身對象
                   //執行到這一步,匹配的文本內容是:s替換的文本abcdg
                   boolean boo = matcher.find();//true
                   System.out.println("第一次查找"+boo);
                   boo= matcher.find();//false
                   System.out.println("第二次查找"+boo);
                   Matcher restMatcher = matcher.reset();
                   System.out.println("調用reset方法返回的對象其實就是本對象" + (restMatcher == matcher));
                   boo= matcher.find();
                   System.out.println("第三次查找"+boo);//true
                   //查看匹配器的信息,沒啥用
                   System.out.println(matcher.toMatchResult());
		appendReplacement()使用指定字符串替換文本中匹配到的內容,並返回最後匹配到的內容之前的內容。
       		  //appendReplacement(StringBuffersb, String replacement) 從頭開始查找並替換匹配到的內容,直到匹配到最後一位,並且將從頭到該位的內容輸入到sb中  
                   regex= "abcd";
                   text= "+++++abcd+++++abcd++++";
                   pattern= Pattern.compile(regex);
                   matcher= pattern.matcher(text);
                   String Buffersb = new StringBuffer();
                   while(matcher.find()){
                            matcher.appendReplacement(sb,"X");
                   }
                   System.out.println("從開始替換匹配文本到結束:"+ sb);

appendTail():我們發現,使用替換方法,後面的內容沒了,那麼就可以使用該方法,將之後的內容添加到sb緩衝區中。

              

   //appendTail將之前匹配到最後一次文本的之後內容加到sb中
                   matcher.appendTail(sb);
                   System.out.println("將之前匹配到最後一次的位置之後的文本也加入到sb中:" + sb);

 

接下來看一下常用的正則語句是如何使用的:

下面表格是從網上抄的,表格之後附有我敲的代碼供參考:

\

將下一字符標記爲特殊字符、文本、反向引用或八進制轉義符。例如,"n"匹配字符"n""\n"匹配換行符。序列"\\"匹配"\""\("匹配"("

^

匹配輸入字符串開始的位置。如果設置了 RegExp 對象的 Multiline 屬性,^還會與"\n""\r"之後的位置匹配。

$

匹配輸入字符串結尾的位置。如果設置了 RegExp 對象的 Multiline 屬性,$還會與"\n""\r"之前的位置匹配。

*

零次或多次匹配前面的字符或子表達式。例如,zo*匹配"z""zoo"*等效於 {0,}

+

一次或多次匹配前面的字符或子表達式。例如,"zo+""zo""zoo"匹配,但與"z"不匹配。+等效於 {1,}

?

零次或一次匹配前面的字符或子表達式。例如,"do(es)?"匹配"do""does"中的"do"?等效於 {0,1}

{n}

是非負整數。正好匹配 n 次。例如,"o{2}""Bob"中的"o"不匹配,但與"food"中的兩個"o"匹配。

{n,}

是非負整數。至少匹配 次。例如,"o{2,}"不匹配"Bob"中的"o",而匹配"foooood"中的所有 o"o{1,}"等效於"o+""o{0,}"等效於"o*"

{n,m}

M  n 是非負整數,其中 n <= m。匹配至少 n 次,至多 m 次。例如,"o{1,3}"匹配"fooooood"中的頭三個 o'o{0,1}'等效於 'o?'。注意:您不能將空格插入逗號和數字之間。

?

當此字符緊隨任何其他限定符(*+?{n}{n,}{n,m})之後時,匹配模式是"非貪心的""非貪心的"模式匹配搜索到的、儘可能短的字符串,而默認的"貪心的"模式匹配搜索到的、儘可能長的字符串。例如,在字符串"oooo"中,"o+?"只匹配單個"o",而"o+"匹配所有"o"

.

匹配除"\r\n"之外的任何單個字符。若要匹配包括"\r\n"在內的任意字符,請使用諸如"[\s\S]"之類的模式。

(pattern)

匹配 pattern 並捕獲該匹配的子表達式。可以使用 $0…$9 屬性從結果"匹配"集合中檢索捕獲的匹配。若要匹配括號字符 ( ),請使用"\("或者"\)"

(?:pattern)

匹配 pattern 但不捕獲該匹配的子表達式,即它是一個非捕獲匹配,不存儲供以後使用的匹配。這對於用"or"字符 (|) 組合模式部件的情況很有用。例如,'industr(?:y|ies)是比 'industry|industries'更經濟的表達式。

(?=pattern)

執行正向預測先行搜索的子表達式,該表達式匹配處於匹配 pattern 的字符串的起始點的字符串。它是一個非捕獲匹配,即不能捕獲供以後使用的匹配。例如,'Windows (?=95|98|NT|2000)'匹配"Windows 2000"中的"Windows",但不匹配"Windows 3.1"中的"Windows"。預測先行不佔用字符,即發生匹配後,下一匹配的搜索緊隨上一匹配之後,而不是在組成預測先行的字符後。

(?!pattern)

執行反向預測先行搜索的子表達式,該表達式匹配不處於匹配 pattern 的字符串的起始點的搜索字符串。它是一個非捕獲匹配,即不能捕獲供以後使用的匹配。例如,'Windows (?!95|98|NT|2000)'匹配"Windows 3.1"中的 "Windows",但不匹配"Windows 2000"中的"Windows"。預測先行不佔用字符,即發生匹配後,下一匹配的搜索緊隨上一匹配之後,而不是在組成預測先行的字符後。

x|y

匹配 x  y。例如,'z|food'匹配"z""food"'(z|f)ood'匹配"zood""food"

[xyz]

字符集。匹配包含的任一字符。例如,"[abc]"匹配"plain"中的"a"

[^xyz]

反向字符集。匹配未包含的任何字符。例如,"[^abc]"匹配"plain""p""l""i""n"

[a-z]

字符範圍。匹配指定範圍內的任何字符。例如,"[a-z]"匹配"a""z"範圍內的任何小寫字母。

[^a-z]

反向範圍字符。匹配不在指定的範圍內的任何字符。例如,"[^a-z]"匹配任何不在"a""z"範圍內的任何字符。

\b

匹配一個字邊界,即字與空格間的位置。例如,"er\b"匹配"never"中的"er",但不匹配"verb"中的"er"

\B

非字邊界匹配。"er\B"匹配"verb"中的"er",但不匹配"never"中的"er"

\cx

匹配 x 指示的控制字符。例如,\cM匹配 Control-M或回車符。x 的值必須在 A-Z a-z 之間。如果不是這樣,則假定 c 就是"c"字符本身。

\d

數字字符匹配。等效於 [0-9]

\D

非數字字符匹配。等效於 [^0-9]

\f

換頁符匹配。等效於 \x0c \cL

\n

換行符匹配。等效於 \x0a \cJ

\r

匹配一個回車符。等效於 \x0d \cM

\s

匹配任何空白字符,包括空格、製表符、換頁符等。與 [ \f\n\r\t\v]等效。

\S

匹配任何非空白字符。與 [^ \f\n\r\t\v]等效。

\t

製表符匹配。與 \x09 \cI等效。

\v

垂直製表符匹配。與 \x0b \cK等效。

\w

匹配任何字類字符,包括下劃線。與"[A-Za-z0-9_]"等效。

\W

與任何非單詞字符匹配。與"[^A-Za-z0-9_]"等效。

\xn

匹配 n,此處的 n 是一個十六進制轉義碼。十六進制轉義碼必須正好是兩位數長。例如,"\x41"匹配"A""\x041""\x04"&"1"等效。允許在正則表達式中使用 ASCII 代碼。

\num

匹配 num,此處的 num 是一個正整數。到捕獲匹配的反向引用。例如,"(.)\1"匹配兩個連續的相同字符。

\n

標識一個八進制轉義碼或反向引用。如果 \n 前面至少有 n 個捕獲子表達式,那麼 n 是反向引用。否則,如果 n 是八進制數 (0-7),那麼 n 是八進制轉義碼。

\nm

標識一個八進制轉義碼或反向引用。如果 \nm 前面至少有 nm 個捕獲子表達式,那麼 nm 是反向引用。如果 \nm 前面至少有 n 個捕獲,則 n 是反向引用,後面跟有字符 m。如果兩種前面的情況都不存在,則 \nm 匹配八進制值 nm,其中 n m 是八進制數字 (0-7)

\nml

 n 是八進制數 (0-3)m  l 是八進制數 (0-7) 時,匹配八進制轉義碼 nml

\un

匹配 n,其中 n 是以四位十六進制數表示的 Unicode 字符。例如,\u00A9匹配版權符號 (©)

       下面代碼是我對上表的一個簡單的練習:  

import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class TestRegex2{
         public static void main(String[] args){
          
                   //匹配字符
                   String regex = "abc";
                   String text ="aaabcddfabcasf";
                           
        
                   //[abc]匹配括號中一個成員
                   String regex = "[abc]";
                   String text ="afacsbdfa";
        
                   //在中括號中代表非,除了該括號字符之外任意字符
                   String regex = "[^abc]";
                   String text ="a1f-acs+bd4Wfa";
        
                   //取範圍內字符[a-zA-Z][a-z][1-9]
                   String regex = "[1-9a-e]";
                   String text ="a1f-acs+bd4Wfa";
                  
                   //並集
                   String regex = "[a-c[f-l]]";
                   String text ="a1f-acs+bd4fjklWfzzzxxa";
        
                   //交集  取 a-f 和e-j 的交集 ef
                   String regex = "[a-f&&[e-j]]";
                   String text ="a1f-aeecs+bfd4fjfklWfffzzzxxa";
        
                   //取a-z,不包含e-f字母
                   //[^e-f]:除了e、f所有的字母、數字、符號
                   String regex = "[a-z&&[^e-f]]";
                   String text ="a1f-aeecs+bfd4fjfklWfffzzzxxa";
                  
                   //.:任何字符
                   String regex = ".";
                   String text ="a1f-aeecs+bfd4fjfklWfffzzzxxa";
                  
                   //\d:數字0-9 ;\w:a-zA-Z_0-9;\s:空白字符,3個字母的大寫相當於取反
                   String regex = "\\d";
                   String text ="a1f-aeecs+bfd4fjfklWfffzzzxxa";
 
                   //^:以之後的字符進行開始進行匹配,放在語句第一位
                   //$:行的結尾,以前面字符做匹配
                   String regex = "......a$";
                   String text ="aaa-aaa";
        
                   //匹配次數 ?:0或1次,+:1次及以上,*:0次及以上
                   String regex = "a+";
                   String text ="bbbb";
                  
                   //{n}:代表前面字符出現n次,{n,}:n次及以上,{n,m}n~m次
                   String regex = "[1-9]\\d{17}";
                   String text ="112345678912345678";
        
                   //驗證QQ 5~10
                   String regex = "[1-9]\\d{4,9}$";
                   String text ="10086231231231231213231231";
                  
                   //|:或者
                   String regex = "abc|ABC|XXX";
                   String text ="ABCabcadfXXXasABCdabcf";
          
                   //驗證身份證號
                   String regex = "[1-9]\\d{17}|[1-9]\\d{14}";
                   String text ="142212199812122222";
                  
                   //驗證QQ號
                   String regex = "[1-9]\\d{4,9}";
                   String text ="12345";
        
                   //驗證手機號
                   String regex = "^1[3|5|7|8|9]\\d{9}";
                   String text ="15666666661";
        
                   //驗證郵箱 郵箱名爲6-20位,郵箱服務商域名2~10位,結尾只能匹配com,net,cn格式
                   String regex = "^\\w{6,20}@\\w{2,10}\\.com|net|cn";
                   String text ="[email protected]";
                  
 
                   //驗證網址http://www.開頭,域名主體爲1-10位a-zA-Z0-9字符,結尾只能是以.com cn net org xin結尾的網址
                   String regex = "^http://w{3}\\.\\w{1,10}\\.com|cn|net|org|xin";
                   String text ="http://www.sohu.com";
                  
                   //驗證賬號:a-zA-Z0-9_$,必須以字母打頭,6-16位
                   String regex = "^\\w[\\w|_|$|\\d]{5,15}";
                   String text ="httpww";
                  
                   //驗證生日 格式 1999-12-12,月份不能大於12,月份中的日期不能大於31
                   String regex = "^[12]\\d{3}-[01]\\d-([12]\\d)|(3[01])";
                   String text ="1991-12-32";
                  
                  
                   //創建正則對象
                   Pattern pattern = Pattern.compile(regex);
                   Matcher matcher = pattern.matcher(text);
                   System.out.println(matcher.matches()?"匹配成功":"匹配失敗") ;
                  
                   //輸出匹配的內容
                  while(matcher.find()){
                            Stringresult = matcher.group();
                            System.out.println(result);
                   }
                  
         }
}


匹配器對象Matcher的替換方法: 

 

		//appendReplacement(StringBuffersb, String replacement) 從頭開始查找並替換匹配到的內容,直到匹配到最後一位,並且將從頭到該位的內容輸入到sb中       
                   regex= "abcd";
                   text= "+++++abcd+++++abcd++++";
                   pattern= Pattern.compile(regex);
                   matcher= pattern.matcher(text);
                   StringBuffer sb = new StringBuffer();
                   while(matcher.find()){
                            matcher.appendReplacement(sb,"X");
                   }
                   System.out.println("從開始替換匹配文本到結束:"+ sb);
                   //appendTail將之前匹配到最後一次文本的之後內容加到sb中
                   matcher.appendTail(sb);
                   System.out.println("將之前匹配到最後一次的位置之後的文本也加入到sb中:" + sb);

分組語句: 

	  //分組語句(),結合group方法,傳參獲取指定組的匹配內容
	/
	*如下正則語句,將會匹配text文本的前11位字符,是沒有問題的
	*String regex = "至尊寶至尊小寶至尊大寶";
	/
	//但是,我現在加上括號以後,匹配的結果和沒有加括號一樣,都是前11位字符
	String regex = "(至尊寶)(至尊小寶)(至尊大寶)";
	String text ="至尊寶至尊小寶至尊大寶秦祥林秦漢至尊玉";
         Pattern pattern = Pattern.compile(regex);
                   Matcher matcher = pattern.matcher(text);
                   if(matcher.find ()){
                            Stringgroup = matcher.group();
                            System.out.println(group);
                           
                   }


那麼,區別在哪兒?既然是分組語句,那麼我們可以從匹配器的group方法中看到區別,在api中,group是可以傳參的,傳參int類型,當傳入x數值時,那麼返回的將會是正則語句中第x個括號中的匹配內容,當傳入0時,返回整個匹配到的語句,如下案例: 


	//我現在加上括號以後,匹配的結果和沒有加括號一樣,都是前11位字符
	String regex = "(至尊寶)(至尊小寶)(至尊大寶)";
	String text ="至尊寶至尊小寶至尊大寶秦祥林秦漢至尊玉";
         Pattern pattern = Pattern.compile(regex);
                   Matcher matcher = pattern.matcher(text);
                   if(matcher.find ()){
                            //打印結果爲至尊寶
                            //String group = matcher.group(1);
                            //System.out.println(group);
 
                            //打印結果爲至尊小寶
                            String group = matcher.group(2);
                            System.out.println(group);
                           
 
                            //打印結果爲:至尊寶至尊小寶至尊大寶
                            String group = matcher.group(0);
                            System.out.println(group);
                           
                   }


注意:如果group傳入的參數的分組序號並不存在,如正則語句只分了2個組,但是group語句訪第3個子語句,就會報錯!

 其實分組語句還有一個好處,就是給語句進行分組,達到優先級匹配的效果,如下是我寫的一個正則語句匹配身份證號,當然並不是那麼完美,但是可以看出,下面的分組語句也起到了優先級的效果:

String regex = "^[1-9]\\d{5}(19[0-9]{2}|200[0-9]|201[0-7])(0[0-9]|1[0-2])([012][0-9]|3[01])\\d{3}[0-9|X]";
String text ="35123429800231112X";

預測語句:

	//(?:)向後匹配並將其作爲捕獲的內容
         //語法解析:至尊後面只要有大寶、玉、小寶3個成員中的一個,就可以匹配成功,並且將括號中的成員也作爲匹配到的內容,如下案例,匹配到的內容就是至尊大寶、至尊玉、至尊小寶:
         String regex = "至尊(?:大寶|玉|小寶)";
         String text ="至尊寶至尊小寶至尊大寶秦祥林秦漢至尊玉";
         Pattern pattern = Pattern.compile(regex);
                   Matcher matcher = pattern.matcher(text);
                   if(matcher.find()){
                            String group = matcher.group();
                            System.out.println(group);
                           
                   }
         //(?=)向後匹配,預測語句其後包含括號中內容,但不捕獲
         //語法解析,至尊後面只要有大寶、玉、小寶三個成員中的一個,就會匹配成功,但是匹配結果並不會包含這三個成員,也就是說,該語句的匹配到的內容是:至尊、至尊、至尊
         String regex = "至尊(?=大寶|玉|小寶)";
         String text ="至尊寶至尊小寶至尊大寶秦祥林秦漢至尊玉";
         Pattern pattern = Pattern.compile(regex);
                   Matchermatcher = pattern.matcher(text);
                   if(matcher.find()){
                            String group = matcher.group();
                            System.out.println(group);
                           
                   }
         //(?!)向後匹配,預測語句之後不包含括號內容,但不捕獲
         //語法解析:至尊後面只要不包含大寶、玉、小寶的字樣,就可以匹配成功,如下案例匹配到的內容是:至尊寶,但是括號中的不包含的內容“寶”字也不會被捕獲,即他的功能只是預測一下至尊後面是不是不包含某些字眼,並不會將該字眼之外的內容捕獲放到匹配到的內容當中,所以如下結果打印爲:至尊
         String regex = "至尊(?!大寶|玉|小寶)";       
         String text ="至尊寶至尊小寶至尊大寶秦祥林秦漢至尊玉";
         Pattern pattern = Pattern.compile(regex);
         Matcher matcher = pattern.matcher(text);
         if(matcher.find()){
                   Stringgroup = matcher.group();
                   System.out.println(group);     
         }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章