天天看點

Java正規表達式以及Pattern類和Matcher類

轉自文章《詳解Java正規表達式中Pattern類和Matcher類》http://www.jb51.net/article/100673.htm

文章《Pattern和Matcher詳解(字元串比對和位元組碼)》https://blog.csdn.net/u010700335/article/details/44616451

java.util.regex是一個用正規表達式所訂制的模式來對字元串進行比對工作的類庫包。包括兩個類Pattern和Matcher Pattern,Pattern是一個正規表達式經編譯後的表現模式。Matcher對象是一個狀态機器,它依據Pattern對象做為比對模式對字元串展開比對檢查。

前言

本文将介紹Java正規表達式中的Pattern類與Matcher類。首先我們要清楚指定為字元串的正規表達式必須首先被編譯為pattern類的執行個體。是以如何更好的了解這兩個類,是程式設計人員必須知道的。

以下我們就分别來看看這兩個類:

一、捕獲組的概念

捕獲組可以通過從左到右計算其開括号來編号,編号是從1 開始的。例如,在表達式 ((A)(B(C)))中,存在四個這樣的組:

1 2 3 4

1

((A)(B(C)))

2

(A)

3

(B(C))

4

(C)

組零始終代表整個表達式。 以 (?) 開頭的組是純的非捕獲 組,它不捕獲文本,也不針對組合計進行計數。

與組關聯的捕獲輸入始終是與組最近比對的子序列。如果由于量化的緣故再次計算了組,則在第二次計算失敗時将保留其以前捕獲的值(如果有的話)例如,将字元串"aba" 與表達式(a(b)?)+ 相比對,會将第二組設定為 "b"。在每個比對的開頭,所有捕獲的輸入都會被丢棄。

二、詳解Pattern類和Matcher類

java正規表達式通過java.util.regex包下的Pattern類與Matcher類實作(建議在閱讀本文時,打開java API文檔,當介紹到哪個方法時,檢視java API中的方法說明,效果會更佳).

Pattern類用于建立一個正規表達式,也可以說建立一個比對模式,它的構造方法是私有的,不可以直接建立,但可以通過

Pattern.complie(String regex)

簡單工廠方法建立一個正規表達式,

Java代碼示例:

1 2

Pattern p=Pattern.compile(

"\\w+"

);

p.pattern();

//傳回 \w+

pattern()

傳回正規表達式的字元串形式,其實就是傳回

Pattern.complile(String regex)

的regex參數

1.Pattern.split(CharSequence input)

Pattern有一個

split(CharSequence input)

方法,用于分隔字元串,并傳回一個String[],我猜

String.split(String regex)

就是通過

Pattern.split(CharSequence input)

來實作的.

Java代碼示例:

1 2

Pattern p=Pattern.compile(

"\\d+"

);

String[] str=p.split(

"我的QQ是:456456我的電話是:0532214我的郵箱是:[email protected]"

);

結果:str[0]="我的QQ是:" str[1]="我的電話是:" str[2]="我的郵箱是:[email protected]"

2.Pattern.matcher(String regex,CharSequence input)是一個靜态方法,用于快速比對字元串,該方法适合用于隻比對一次,且比對全部字元串.

Java代碼示例:

1 2 3

Pattern.matches(

"\\d+"

,

"2223"

);

//傳回true

Pattern.matches(

"\\d+"

,

"2223aa"

);

//傳回false,需要比對到所有字元串才能傳回true,這裡aa不能比對到

Pattern.matches(

"\\d+"

,

"22bb23"

);

//傳回false,需要比對到所有字元串才能傳回true,這裡bb不能比對到

3.Pattern.matcher(CharSequence input)

說了這麼多,終于輪到Matcher類登場了,

Pattern.matcher(CharSequence input)

傳回一個Matcher對象.

Matcher類的構造方法也是私有的,不能随意建立,隻能通過

Pattern.matcher(CharSequence input)

方法得到該類的執行個體.

Pattern類隻能做一些簡單的比對操作,要想得到更強更便捷的正則比對操作,那就需要将Pattern與Matcher一起合作.Matcher類提供了對正規表達式的分組支援,以及對正規表達式的多次比對支援.

Java代碼示例:

1 2 3

Pattern p=Pattern.compile(

"\\d+"

);

Matcher m=p.matcher(

"22bb23"

);

m.pattern();

//傳回p 也就是傳回該Matcher對象是由哪個Pattern對象的建立的

4.Matcher.matches()/ Matcher.lookingAt()/ Matcher.find()

Matcher類提供三個比對操作方法,三個方法均傳回boolean類型,當比對到時傳回true,沒比對到則傳回false

matches()

對整個字元串進行比對,隻有整個字元串都比對了才傳回true

Java代碼示例:

1 2 3 4 5

Pattern p=Pattern.compile(

"\\d+"

);

Matcher m=p.matcher(

"22bb23"

);

m.matches();

//傳回false,因為bb不能被\d+比對,導緻整個字元串比對未成功.

Matcher m2=p.matcher(

"2223"

);

m2.matches();

//傳回true,因為\d+比對到了整個字元串

我們現在回頭看一下

Pattern.matcher(String regex,CharSequence input)

,它與下面這段代碼等價

Pattern.compile(regex).matcher(input).matches()

lookingAt()

對前面的字元串進行比對,隻有比對到的字元串在最前面才傳回true

Java代碼示例:

1 2 3 4 5

Pattern p=Pattern.compile(

"\\d+"

);

Matcher m=p.matcher(

"22bb23"

);

m.lookingAt();

//傳回true,因為\d+比對到了前面的22

Matcher m2=p.matcher(

"aa2223"

);

m2.lookingAt();

//傳回false,因為\d+不能比對前面的aa

find()

對字元串進行比對,比對到的字元串可以在任何位置.

Java代碼示例:

1 2 3 4 5 6 7 8 9

Pattern p=Pattern.compile(

"\\d+"

);

Matcher m=p.matcher(

"22bb23"

);

m.find();

//傳回true

Matcher m2=p.matcher(

"aa2223"

);

m2.find();

//傳回true

Matcher m3=p.matcher(

"aa2223bb"

);

m3.find();

//傳回true

Matcher m4=p.matcher(

"aabb"

);

m4.find();

//傳回false

5.Mathcer.start()/ Matcher.end()/ Matcher.group()

當使用

matches()

,

lookingAt()

,

find()

執行比對操作後,就可以利用以上三個方法得到更詳細的資訊.

start()

傳回比對到的子字元串在字元串中的索引位置.

end()

傳回比對到的子字元串的最後一個字元在字元串中的索引位置.

group()

傳回比對到的子字元串

Java代碼示例:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

Pattern p=Pattern.compile(

"\\d+"

);

Matcher m=p.matcher(

"aaa2223bb"

);

m.find();

//比對2223

m.start();

//傳回3

m.end();

//傳回7,傳回的是2223後的索引号

m.group();

//傳回2223

Mathcer m2=m.matcher(

"2223bb"

);

m.lookingAt();

//比對2223

m.start();

//傳回0,由于lookingAt()隻能比對前面的字元串,是以當使用lookingAt()比對時,start()方法總是傳回0

m.end();

//傳回4

m.group();

//傳回2223

Matcher m3=m.matcher(

"2223bb"

);

m.matches();

//比對整個字元串

m.start();

//傳回0,原因相信大家也清楚了

m.end();

//傳回6,原因相信大家也清楚了,因為matches()需要比對所有字元串

m.group();

//傳回2223bb

說了這麼多,相信大家都明白了以上幾個方法的使用,該說說正規表達式的分組在java中是怎麼使用的.

start()

,

end()

 ,

group()

均有一個重載方法它們是

start(int i)

,

end(int i)

,

group(int i)

專用于分組操作,Mathcer類還有一個

groupCount()

用于傳回有多少組.

Java代碼示例:

1 2 3 4 5 6 7 8 9 10

Pattern p=Pattern.compile(

"([a-z]+)(\\d+)"

);

Matcher m=p.matcher(

"aaa2223bb"

);

m.find();

//比對aaa2223

m.groupCount();

//傳回2,因為有2組

m.start(

1

);

//傳回0 傳回第一組比對到的子字元串在字元串中的索引号

m.start(

2

);

//傳回3

m.end(

1

);

//傳回3 傳回第一組比對到的子字元串的最後一個字元在字元串中的索引位置.

m.end(

2

);

//傳回7

m.group(

1

);

//傳回aaa,傳回第一組比對到的子字元串

m.group(

2

);

//傳回2223,傳回第二組比對到的子字元串

現在我們使用一下稍微進階點的正則比對操作,例如有一段文本,裡面有很多數字,而且這些數字是分開的,我們現在要将文本中所有數字都取出來,利用java的正則操作是那麼的簡單.

Java代碼示例:

1 2 3 4 5

Pattern p=Pattern.compile(

"\\d+"

);

Matcher m=p.matcher(

"我的QQ是:456456 我的電話是:0532214 我的郵箱是:[email protected]"

);

while

(m.find()) {

System.out.println(m.group());

}

輸出:

1 2 3

456456

0532214

123

如将以上

while()

循環替換成

1 2 3 4 5

while

(m.find()) {

System.out.println(m.group());

System.out.print(

"start:"

+m.start());

System.out.println(

" end:"

+m.end());

}

則輸出:

1 2 3 4 5 6

456456

start:

6

end:

12

0532214

start:

19

end:

26

123

start:

36

end:

39

現在大家應該知道,每次執行比對操作後

start()

,

end()

,

group()

三個方法的值都會改變,改變成比對到的子字元串的資訊,以及它們的重載方法,也會改變成相應的資訊.

注意:隻有當比對操作成功,才可以使用

start()

,

end()

,

group()

三個方法,否則會抛出

java.lang.IllegalStateException

,也就是當

matches()

,

lookingAt()

,

find()

其中任意一個方法傳回true時,才可以使用.

三、Java正規表達式

 現在通過一些實驗來說明正規表達式的比對規則,這兒是Greedy方式

  .              任何字元

 a?             a一次或一次也沒有

 a*             a零次或多次

 a+            a一次或多次

 a{n}?      a恰好 n 次

 a{n,}?       a至少n次 

 a{n,m}?   a至少n次,但是不超過m次

//初步認識. * + ?

        p("a".matches("."));//true

        p("aa".matches("aa"));//true

        p("aaaa".matches("a*"));//true

        p("aaaa".matches("a+"));//true

        p("".matches("a*"));//true

        p("aaaa".matches("a?"));//false

        p("".matches("a?"));//true

        p("a".matches("a?"));//true

        p("1232435463685899".matches("\\d{3,100}"));//true

        p("192.168.0.aaa".matches("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"));//false

        p("192".matches("[0-2][0-9][0-9]"));//true [abc]                        a、b 或 c(簡單類)

[^abc]                      任何字元,除了 a、b 或 c(否定)

[a-zA-Z]                   a 到 z 或 A 到 Z,兩頭的字母包括在内(範圍)

[a-d[m-p]]                a 到 d 或 m 到 p:[a-dm-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](減去)

//範圍

        p("a".matches("[abc]"));//true

        p("a".matches("[^abc]"));//false

        p("A".matches("[a-zA-Z]"));//true

        p("A".matches("[a-z]|[A-Z]"));//true

        p("A".matches("[a-z[A-Z]]"));//true

        p("R".matches("[A-Z&&[RFG]]"));//true

\d                          數字:[0-9]

\D                         非數字: [^0-9]

\s                          空白字元:[ \t\n\x0B\f\r]

\S                         非空白字元:[^\s]

\w                         單詞字元:[a-zA-Z_0-9]

\W                        非單詞字元:[^\w]

         //認識\s \w \d \

        p("\n\r\t".matches("\\s(4)"));//false

        p(" ".matches("\\S"));//false

        p("a_8 ".matches("\\w(3)"));//false

        p("abc888&^%".matches("[a-z]{1,3}\\d+[&^#%]+"));//true

        p("\\".matches("\\\\"));//true

 邊界比對器

      ^                                          行的開頭

      $                                          行的結尾

      \b                                        單詞邊界

      \B                                        非單詞邊界

      \A                                        輸入的開頭

      \G                                       上一個比對的結尾

      \Z                                       輸入的結尾,僅用于最後的結束符(如果有的話)

      \z                                       輸入的結尾

//邊界比對

        p("hello sir".matches("^h.*"));//true

        p("hello sir".matches(".*ir$"));//true

        p("hello sir".matches("^h[a-z]{1,3}o\\b.*"));//true

        p("hellosir".matches("^h[a-z]{1,3}o\\b.*"));//false

        //空白行:一個或多個(空白并且非換行符)開頭,并以換行符結尾

        p(" \n".matches("^[\\s&&[^\\n]]*\\n$"));//true

重點說明

表示<>之間有任意一個(含)字元以上,括号表示捕獲組,比對後可以單獨提取出括号内的内容,?代表最短比對,比如<asdf>>>這樣的輸入,有?會比對成<asdf>,沒有?會比對整個<asdf>>>。

str.ReplactAll("<(.)+?>","")就是把所有<>間有一個字元以上的文字都替換為空。比如

asdf<1234>jkl<>會變成asdfjkl<>

另外要是str_line.replaceAll("&(.)+?;"," ") 是将&開頭的包含任意字元的右面的最短比對并以;結束的都替換成為空