Java中的正則表達(dá)式知識(shí)點(diǎn)總結(jié)

前段時(shí)間做聊天消息的解析,涉及到要在群消息中查找@的人,需要把@后面的用戶昵稱解析出來,首先想到的當(dāng)然就是用正則來實(shí)現(xiàn)了,于是一頓操作外加度娘加持。

public static List<String> findRegex(String p,String s){
        Pattern pattern = Pattern.compile(p);
        Matcher matcher = pattern.matcher(s);

        List<String> list=new ArrayList<>();
        while (matcher.find()) {
                list.add(matcher.group());
         }
         return list;
    }

//引用的地方調(diào)用
//@開頭,空格結(jié)尾
List<String> list=findRegex("(?<=\\@)(\\S+)(?=\\s)",msg);

這里面涉及知識(shí)點(diǎn):

  1. Java的兩個(gè)類Pattern,Matcher
    Pattern.compile生成Pattern
    find()匹配
    group()得到匹配結(jié)果

2.正則表達(dá)式。
零寬斷言用于匹配@來頭及空格結(jié)尾

具體的用法含義請(qǐng)查看下面詳細(xì)內(nèi)容

1.Java中的正則表達(dá)式類

java.util.regex 包主要包括以下三個(gè)類:

Pattern 類:

pattern 對(duì)象是一個(gè)正則表達(dá)式的編譯表示。

構(gòu)造

Pattern 類沒有公共構(gòu)造方法。要?jiǎng)?chuàng)建一個(gè) Pattern 對(duì)象,你必須首先調(diào)用其公共靜態(tài)編譯方法,它返回一個(gè) Pattern 對(duì)象。該方法接受一個(gè)正則表達(dá)式作為它的第一個(gè)參數(shù)。

Pattern p=Pattern.compile("\\S+"); 
p.pattern();//返回Pattern.complile(String regex)的regex參數(shù)  \S+

compile( )方法還有一個(gè)版本,它需要一個(gè)控制正則表達(dá)式的匹配行為的參數(shù):

Pattern Pattern.compile(String regex, int flag)

flag的取值范圍如下:

編譯標(biāo)志 效果
Pattern.CANON_EQ 當(dāng)且僅當(dāng)兩個(gè)字符的"正規(guī)分解(canonical decomposition)"都完全相同的情況下,才認(rèn)定匹配。比如用了這個(gè)標(biāo)志之后,表達(dá)式"a/u030A"會(huì)匹配"?"。默認(rèn)情況下,不考慮"規(guī)范相等性(canonical equivalence)"。
Pattern.CASE_INSENSITIVE(?i) 默認(rèn)情況下,大小寫不敏感的匹配只適用于US-ASCII字符集。這個(gè)標(biāo)志能讓表達(dá)式忽略大小寫進(jìn)行匹配。要想對(duì)Unicode字符進(jìn)行大小不明感的匹配,只要將UNICODE_CASE與這個(gè)標(biāo)志合起來就行了。
Pattern.COMMENTS(?x) 在這種模式下,匹配時(shí)會(huì)忽略(正則表達(dá)式里的)空格字符(注:不是指表達(dá)式里的"http://s",而是指表達(dá)式里的空格,tab,回車之類)。注釋從#開始,一直到這行結(jié)束??梢酝ㄟ^嵌入式的標(biāo)志來啟用Unix行模式。
Pattern.DOTALL(?s) 在這種模式下,表達(dá)式'.'可以匹配任意字符,包括表示一行的結(jié)束符。默認(rèn)情況下,表達(dá)式'.'不匹配行的結(jié)束符。
Pattern.MULTILINE (?m) 在這種模式下,'^'和''分別匹配一行的開始和結(jié)束。此外,'^'仍然匹配字符串的開始,''也匹配字符串的結(jié)束。默認(rèn)情況下,這兩個(gè)表達(dá)式僅僅匹配字符串的開始和結(jié)束。
Pattern.UNICODE_CASE (?u) 在這個(gè)模式下,如果你還啟用了CASE_INSENSITIVE標(biāo)志,那么它會(huì)對(duì)Unicode字符進(jìn)行大小寫不明感的匹配。默認(rèn)情況下,大小寫不明感的匹配只適用于US-ASCII字符集。
Pattern.UNIX_LINES (?d) 在這個(gè)模式下,只有'/n'才被認(rèn)作一行的中止,并且與'.','^',以及'$'進(jìn)行匹配。

在這些標(biāo)志里面,Pattern.CASE_INSENSITIVE,Pattern.MULTILINE,以及Pattern.COMMENTS是最有用的(其中Pattern.COMMENTS還能幫我們把思路理清楚,并且/或者做文檔)。注意,你可以用在表達(dá)式里插記號(hào)的方式來啟用絕大多數(shù)的模式。這些記號(hào)就在上面那張表的各個(gè)標(biāo)志的下面。可以用"OR" ('|')運(yùn)算符把這些標(biāo)志合使用

方法

1.Pattern.split(CharSequence input)
Pattern有一個(gè)split(CharSequence input)方法,用于分隔字符串,并返回一個(gè)String[],我猜String.split(String regex)就是通過Pattern.split(CharSequence input)來實(shí)現(xiàn)的.

Pattern p=Pattern.compile(",");
        String[] str=p.split("abc,444,666,ddd,rr");
        if(str!=null){
            for(int i=0;i<str.length;i++){
                System.out.println(String.format("第%d個(gè)值為%s",i,str[i]));
            }
        }

輸出為

第0個(gè)值為abc
第1個(gè)值為444
第2個(gè)值為666
第3個(gè)值為ddd
第4個(gè)值為rr

2.Pattern.matcher(String regex,CharSequence input)是一個(gè)靜態(tài)方法,用于快速匹配字符串,該方法適合用于只匹配一次,且匹配全部字符串.
Java代碼示例:

Pattern.matches("\\d+","9527");//返回true 
Pattern.matches("\\d+","9527aa");//返回false,需要匹配到所有字符串才能返回true,這里aa不能匹配到 
Pattern.matches("\\d+","22bb23");//返回false,需要匹配到所有字符串才能返回true,這里bb不能匹配到

3.Pattern.matcher(CharSequence input)
說了這么多,終于輪到Matcher類登場(chǎng)了,Pattern.matcher(CharSequence input)返回一個(gè)Matcher對(duì)象.
Matcher類的構(gòu)造方法也是私有的,不能隨意創(chuàng)建,只能通過Pattern.matcher(CharSequence input)方法得到該類的實(shí)例.
Pattern類只能做一些簡(jiǎn)單的匹配操作,要想得到更強(qiáng)更便捷的正則匹配操作,那就需要將Pattern與Matcher一起合作.Matcher類提供了對(duì)正則表達(dá)式的分組支持,以及對(duì)正則表達(dá)式的多次匹配支持.

Pattern p=Pattern.compile("\\d+"); 
Matcher m=p.matcher("22ssd23"); 
m.pattern();//返回p 也就是返回該Matcher對(duì)象是由哪個(gè)Pattern對(duì)象的創(chuàng)建的

Matcher 類:

Matcher對(duì)象是對(duì)輸入字符串進(jìn)行解釋和匹配操作的引擎。與Pattern 類一樣,Matcher 也沒有公共構(gòu)造方法。你需要調(diào)用 Pattern 對(duì)象的 matcher 方法來獲得一個(gè) Matcher 對(duì)象。

匹配操作

Matcher類提供三個(gè)匹配操作方法,三個(gè)方法均返回boolean類型,當(dāng)匹配到時(shí)返回true,沒匹配到則返回false

  • matches()對(duì)整個(gè)字符串進(jìn)行匹配,只有整個(gè)字符串都匹配了才返回true
Pattern p=Pattern.compile("\\d+"); 
Matcher m=p.matcher("22bb23"); 
m.matches();//返回false,因?yàn)閎b不能被\d+匹配,導(dǎo)致整個(gè)字符串匹配未成功. 
Matcher m2=p.matcher("9527"); 
m2.matches();//返回true,因?yàn)閈d+匹配到了整個(gè)字符串

我們現(xiàn)在回頭看一下Pattern.matcher(String regex,CharSequence input),它與下面這段代碼等價(jià)
Pattern.compile(regex).matcher(input).matches()

  • lookingAt() 對(duì)前面的字符串進(jìn)行匹配,只有匹配到的字符串在最前面才返回 true
Pattern p=Pattern.compile("\\d+"); 
Matcher m=p.matcher("22bb23"); 
m.lookingAt();//返回true,因?yàn)閈d+匹配到了前面的22 
Matcher m2=p.matcher("aa9527"); 
m2.lookingAt();//返回false,因?yàn)閈d+不能匹配前面的aa
  • find()對(duì)字符串進(jìn)行匹配,匹配到的字符串可以在任何位置.
Pattern p=Pattern.compile("\\d+"); 
Matcher m=p.matcher("22bb23"); 
m.find();//返回true 
Matcher m2=p.matcher("aa9527"); 
m2.find();//返回true 
Matcher m3=p.matcher("aa9527bb"); 
m3.find();//返回true 
Matcher m4=p.matcher("aabb"); 
m4.find();//返回false
索引位置

當(dāng)使用matches(),lookingAt(),find()執(zhí)行匹配操作后,利用以上三個(gè)方法得到更詳細(xì)的信息。

  • start()返回匹配到的子字符串在字符串中的索引位置
  • end()返回匹配到的子字符串的最后一個(gè)字符在字符串中的索引位置
  • group()返回匹配到的子字符串
Pattern p=Pattern.compile("\\d+"); 
Matcher m=p.matcher("aaa9527bb"); 
m.find();//匹配9527 
m.start();//返回3 
m.end();//返回7,返回的是9527后的索引號(hào) 
m.group();//返回9527

Mathcer m2=m.matcher("9527bb"); 
m.lookingAt();   //匹配9527 
m.start();   //返回0,由于lookingAt()只能匹配前面的字符串,所以當(dāng)使用lookingAt()匹配時(shí),start()方法總是返回0 
m.end();   //返回4 
m.group();   //返回匹配到的結(jié)果,即9527 

Matcher m3=m.matcher("9527bb"); 
m.matches();   //匹配整個(gè)字符串 
m.start();   //返回0,原因相信大家也清楚了 
m.end();   //返回6,原因相信大家也清楚了,因?yàn)閙atches()需要匹配所有字符串 
m.group();   //返回9527bb

start(),end(),group()均有一個(gè)重載方法它們是start(int i),end(int i),group(int i)專用于分組操作,與參數(shù)為0時(shí)返回的結(jié)果相同,Mathcer類還有一個(gè)groupCount()用于返回有多少組.

Pattern p=Pattern.compile("([a-z]+)(\\d+)"); 
Matcher m=p.matcher("aaa9527bb"); 
m.find();   //匹配aaa9527 
m.groupCount();   //返回2,因?yàn)橛?組 

m.start(0);//與m.start()相同,返回0
m.end(0);//與m.end()相同,返回7

m.start(1);   //返回0 返回第一組匹配到的子字符串在字符串中的索引號(hào) 
m.start(2);   //返回3 
m.end(1);   //返回3 返回第一組匹配到的子字符串的最后一個(gè)字符在字符串中的索引位置. 
m.end(2);   //返回7 
m.group(1);   //返回aaa,返回第一組匹配到的子字符串 
m.group(2);   //返回9527,返回第二組匹配到的子字符串

PatternSyntaxException

PatternSyntaxException 是一個(gè)非強(qiáng)制異常類,它表示一個(gè)正則表達(dá)式模式中的語法錯(cuò)誤。

總結(jié)正則:


java正則

2、正則表達(dá)式語法

元字符

代碼 說明
. 匹配除換行符以外的任意字符
\w 匹配字母或數(shù)字或下劃線或漢字
\s 匹配任意的空白符
\d 匹配數(shù)字
^ 匹配字符串的開始
$ 匹配字符串的結(jié)束
\b 匹配字符串的結(jié)束

重復(fù)

代碼/語法 說明
* 重復(fù)零次或更多次
+ 重復(fù)一次或更多次
? 重復(fù)零次或一次
{n} 重復(fù)n次
{n,} 重復(fù)n次或更多次
{n,m} 重復(fù)n到m次

字符類

想查找數(shù)字,字母或數(shù)字,空白是很簡(jiǎn)單的,因?yàn)橐呀?jīng)有了對(duì)應(yīng)這些字符集合的元字符,但是如果你想匹配沒有預(yù)定義元字符的字符集合(比如元音字母a,e,i,o,u),應(yīng)該怎么辦?
很簡(jiǎn)單,你只需要在方括號(hào)里列出它們就行了,像[aeiou]就匹配任何一個(gè)英文元音字母,[.?!]匹配標(biāo)點(diǎn)符號(hào)(.或?或!)。
我們也可以輕松地指定一個(gè)字符范圍,像[0-9]代表的含意與\d就是完全一致的:一位數(shù)字;同理[a-z0-9A-Z_]也完全等同于\w(如果只考慮英文的話)。

分枝條件

用|把不同的規(guī)則分別表達(dá)。
如:0\d{2}-\d{8}|0\d{3}-\d{7}這個(gè)表達(dá)式能匹配兩種以連字號(hào)分隔的電話號(hào)碼:一種是三位區(qū)號(hào),8位本地號(hào)(如010-12345678),一種是4位區(qū)號(hào),7位本地號(hào)(0376-2233445)。

反義

代碼/語法 說明
\W 匹配任意不是字母,數(shù)字,下劃線,漢字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非數(shù)字的字符
\B 匹配不是單詞開頭或結(jié)束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou這幾個(gè)字母以外的任意字符

分組

重復(fù)單個(gè)字符直接在字符后面加上限定符就行了,但如果想要重復(fù)多個(gè)字符又該怎么辦?你可以用小括號(hào)來指定子表達(dá)式(也叫做分組),然后你就可以指定這個(gè)子表達(dá)式的重復(fù)次數(shù)了,你也可以對(duì)子表達(dá)式進(jìn)行其它一些操作。
使用小括號(hào)指定一個(gè)子表達(dá)式后,匹配這個(gè)子表達(dá)式的文本(也就是此分組捕獲的內(nèi)容)可以在表達(dá)式或其它程序中作進(jìn)一步的處理。捕獲組可以通過從左到右計(jì)算其開括號(hào)來編號(hào)。例如,在表達(dá)式 ((A)(B(C))) 中,存在四個(gè)這樣的組:

  • ((A)(B(C)))
  • (A)
  • (B(C))
  • (C)
    組零始終代表整個(gè)表達(dá)式。

之所以這樣命名捕獲組是因?yàn)樵谄ヅ渲?,保存了與這些組匹配的輸入序列的每個(gè)子序列。捕獲的子序列稍后可以通過 Back 引用在表達(dá)式中使用,也可以在匹配操作完成后從匹配器獲取。

與組關(guān)聯(lián)的捕獲輸入始終是與組最近匹配的子序列。如果由于量化的緣故再次計(jì)算了組,則在第二次計(jì)算失敗時(shí)將保留其以前捕獲的值(如果有的話)例如,將字符串 "aba" 與表達(dá)式 (a(b)?)+ 相匹配,會(huì)將第二組設(shè)置為 "b"。在每個(gè)匹配的開頭,所有捕獲的輸入都會(huì)被丟棄。
以 (?) 開頭的組是純的非捕獲 組,它不捕獲文本,也不針對(duì)組合計(jì)進(jìn)行計(jì)數(shù)。
后向引用用于重復(fù)搜索前面某個(gè)分組匹配的文本。例如:
\b(\w+)\b\s+\1\b可以用來匹配重復(fù)的單詞,像go go, 或者kitty kitty。

也可以自己指定子表達(dá)式的組名。要指定一個(gè)子表達(dá)式的組名,請(qǐng)使用這樣的語法:(?<Word>\w+)(或者把尖括號(hào)換成'也行:(?'Word'\w+)),這樣就把\w+的組名指定為Word了。要反向引用這個(gè)分組捕獲的內(nèi)容,你可以使用\k<Word>,所以上一個(gè)例子也可以寫成這樣:\b(?<Word>\w+)\b\s+\k<Word>\b

零寬斷言

(?=exp)也叫零寬度正預(yù)測(cè)先行斷言,它斷言被匹配的字符串以表達(dá)式exp結(jié)尾但除了結(jié)尾以外的部分。比如\b\w+(?=ing\b),匹配以ing結(jié)尾的單詞的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.時(shí),它會(huì)匹配sing和danc。
(?<=exp)也叫零寬度正回顧后發(fā)斷言,它斷言自身出現(xiàn)的位置的前面能匹配表達(dá)式exp。比如(?<=\bre)\w+\b會(huì)匹配以re開頭的單詞的后半部分(除了re以外的部分),例如在查找reading a book時(shí),它匹配ading。

代碼/語法 說明
(?=exp) 匹配exp前面的位置
(?<=exp) 匹配exp后面的位置
(?!exp) 匹配后面跟的不是exp的位置
(?<!exp) 匹配前面不是exp的位置

注釋

小括號(hào)的另一種用途是通過語法(?#comment)來包含注釋。例如:2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d \d?(?#0-199)。

貪婪與懶惰

語法 說明
*? 重復(fù)任意次,但盡可能少重復(fù)
+? 重復(fù)1次或更多次,但盡可能少重復(fù)
?? 重復(fù)0次或1次,但盡可能少重復(fù)
{n,m}? 重復(fù)n到m次,但盡可能少重復(fù)
{n,}? 重復(fù)n次以上,但盡可能少重復(fù)

當(dāng)正則表達(dá)式中包含能接受重復(fù)的限定符時(shí),通常的行為是(在使整個(gè)表達(dá)式能得到匹配的前提下)匹配盡可能多的字符??紤]這個(gè)表達(dá)式:a.b,它將會(huì)匹配最長(zhǎng)的以a開始,以b結(jié)束的字符串。如果用它來搜索aabab的話,它會(huì)匹配整個(gè)字符串a(chǎn)abab。這被稱為貪婪匹配。
有時(shí),我們更需要懶惰匹配,也就是匹配盡可能少的字符。前面給出的限定符都可以被轉(zhuǎn)化為懶惰匹配模式,只要在它后面加上一個(gè)問號(hào)?。這樣.
?就意味著匹配任意數(shù)量的重復(fù),但是在能使整個(gè)匹配成功的前提下使用最少的重復(fù)?,F(xiàn)在看看懶惰版的例子吧:
a.*?b匹配最短的,以a開始,以b結(jié)束的字符串。如果把它應(yīng)用于aabab的話,它會(huì)匹配aab(第一到第三個(gè)字符)和ab(第四到第五個(gè)字符)。

POSIX 字符類(僅 US-ASCII)

語法 說明
\p{Lower} 小寫字母字符:[a-z]
\p{Upper} 大寫字母字符:[A-Z]
\p{ASCII} 所有 ASCII:[\x00-\x7F]
\p{Alpha} 字母字符:[\p{Lower}\p{Upper}]
\p{Digit} 十進(jìn)制數(shù)字:[0-9]
\p{Alnum} 字母數(shù)字字符:[\p{Alpha}\p{Digit}]
\p{Punct} 標(biāo)點(diǎn)符號(hào):!"#$%&'()*+,-./:;<=>?@[]^_{ }~
\p{Graph} 可見字符:[\p{Alnum}\p{Punct}]
\p{Print} 可打印字符:[\p{Graph}\x20]
\p{Blank} 空格或制表符:[ \t]
\p{Cntrl} 控制字符:[\x00-\x1F\x7F]
\p{XDigit} 十六進(jìn)制數(shù)字:[0-9a-fA-F]
\p{Space} 空白字符:[ \t\n\x0B\f\r]

引用

語法 說明
\ Nothing,但是引用以下字符
\Q Nothing,但是引用所有字符,直到 \E
\E Nothing,但是結(jié)束從 \Q 開始的引用

如:\Q\w+\E表示字符串\w+而不是正則中的單詞字符:[a-zA-Z_0-9]。

其他

語法 說明
\xhh 十六進(jìn)制值為0xhh的字符
\uhhhh 十六進(jìn)制表示為0xhhhh的Unicode字符
\t 制表符Tab
\n 換行符
\r 回車
\f 換頁
\e 轉(zhuǎn)義(Escape)

處理選項(xiàng)

上面介紹了幾個(gè)選項(xiàng)如忽略大小寫,處理多行等,這些選項(xiàng)能用來改變處理正則表達(dá)式的方式。下面是Java中常用的正則表達(dá)式選項(xiàng):

名稱 說明
CASE_INSENSITIVE 匹配時(shí)區(qū)分大小寫
MULTILINE 更改^和的含義,使它們分別在任意一行的行首和行尾匹配,而不僅僅在整個(gè)字符串的開頭和結(jié)尾匹配。(在此模式下,的精確含意是:匹配\n之前的位置以及字符串結(jié)束前的位置.)
DOTALL 在 dotall 模式中,表達(dá)式 . 可以匹配任何字符,包括行結(jié)束符。默認(rèn)情況下,此表達(dá)式不匹配行結(jié)束符。
UNICODE_CASE 指定此標(biāo)志后,由 CASE_INSENSITIVE 標(biāo)志啟用時(shí),不區(qū)分大小寫的匹配將以符合 Unicode Standard 的方式完成。默認(rèn)情況下,不區(qū)分大小寫的匹配假定僅匹配 US-ASCII 字符集中的字符。通過嵌入式標(biāo)志表達(dá)式 (?u) 也可以啟用 Unicode 感知的大小寫折疊。指定此標(biāo)志可能對(duì)性能產(chǎn)生影響。
CANON_EQ 啟用規(guī)范等價(jià)。指定此標(biāo)志后,當(dāng)且僅當(dāng)其完整規(guī)范分解匹配時(shí),兩個(gè)字符才可視為匹配。例如,當(dāng)指定此標(biāo)志時(shí),表達(dá)式 "a\u030A" 將與字符串 "\u00E5" 匹配。默認(rèn)情況下,匹配不考慮采用規(guī)范等價(jià)。不存在可以啟用規(guī)范等價(jià)的嵌入式標(biāo)志字符。指定此標(biāo)志可能對(duì)性能產(chǎn)生影響。
UNIX_LINES 啟用 Unix 行模式。在此模式中,.、^ 和 $ 的行為中僅識(shí)別 '\n' 行結(jié)束符。通過嵌入式標(biāo)志表達(dá)式 (?d) 也可以啟用 Unix 行模式。
LITERAL 指定此標(biāo)志后,指定模式的輸入字符串就會(huì)作為字面值字符序列來對(duì)待。輸入序列中的元字符或轉(zhuǎn)義序列不具有任何特殊意義。標(biāo)志 CASE_INSENSITIVE 和 UNICODE_CASE 在與此標(biāo)志一起使用時(shí)將對(duì)匹配產(chǎn)生影響。其他標(biāo)志都變得多余了。不存在可以啟用字面值解析的嵌入式標(biāo)志字符。
UNICODE_CHARACTER_CLASS
COMMENTS 模式中允許空白和注釋。此模式將忽略空白和在結(jié)束行之前以 # 開頭的嵌入式注釋。通過嵌入式標(biāo)志表達(dá)式 (?x) 也可以啟用注釋模式。

參照YunSoul 舒山

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容