正則表達(dá)式深度解析

  • 正則表達(dá)式(regular expression)是一種可以在許多現(xiàn)代應(yīng)用程序和編程語(yǔ)言中使用的特殊形式的代碼模式和簸】叮可以使用它們來(lái)驗(yàn)證輸入是否符合給定的文本模式揪利,在一大段文字中查找該模式的文本旦装,用其它文本來(lái)替換匹配該模式的文本或者重新組織匹配文本的一部分疏唾,把一塊文本劃分成一系列更小的文本

  • 正則表達(dá)式通常用于兩種任務(wù):1.驗(yàn)證蓄氧,2.搜索/替換。用于驗(yàn)證時(shí)槐脏,通常需要在前后分別加上^和喉童,以匹配整個(gè)待驗(yàn)證字符串;搜索/替換時(shí)是否加上此限定則根據(jù)搜索的要求而定顿天,此外,也有可能要在前后加上\b而不是^和。此表所列的常用正則表達(dá)式柿扣,除個(gè)別外均未在前后加上任何限定页响,請(qǐng)根據(jù)需要,自行處理

元字符

正則表達(dá)式之所以擁有巨大的魔力鸟缕,就是因?yàn)橛?2個(gè)標(biāo)點(diǎn)字符才產(chǎn)生的

$ ( ) * + . ? [ \ ^ { |

它們被稱作元字符晶框,如果想要在下正則表達(dá)式中匹配它們,那么就需要在它們前面用一個(gè)反斜杠\來(lái)進(jìn)行轉(zhuǎn)義懂从。特別應(yīng)該注意的是在這個(gè)列表中并不包含右方括號(hào)]授段、連字符-和右花括號(hào)},前兩個(gè)字符只有在它們位于一個(gè)沒(méi)有轉(zhuǎn)義的[之后才成為元字符番甩,而}只有在一個(gè)沒(méi)有轉(zhuǎn)義的{之后才是元字符侵贵。在任何時(shí)候都沒(méi)有必要對(duì)}進(jìn)行轉(zhuǎn)義

在Java里面,要匹配反斜杠\缘薛,需要使用“\\”窍育,因?yàn)樵谧址锩娌辉试S出現(xiàn)單個(gè)反斜杠\卡睦,所以“\”表示一個(gè)反斜杠,“\\”才能正確匹配到反斜杠\

使用正則記號(hào)<\Q>和<\E>。<\Q>會(huì)抑制所有元字符的含義蔫骂,直到出現(xiàn)<\E>為止么翰。如果漏掉了<\E>,那么在<\Q>之后直到正則表達(dá)式結(jié)束之前的所有字符都會(huì)被當(dāng)作字符文本來(lái)對(duì)待辽旋。所以上面的正則表達(dá)式可以用如下代碼匹配

Pattern p = Pattern.compile("\\Q$()*+.?[\\^{|\\E");

Matcher m = p.matcher("$()*+.?[\\^{|");

匹配單個(gè)字符

除了元字符之外浩嫌,匹配單個(gè)字符直接使用對(duì)應(yīng)的字符來(lái)匹配,當(dāng)然也有一些特殊的字符补胚,如匹配一個(gè)包含ASCII控制字符的字符串:響鈴码耐、退出、換頁(yè)溶其、換行骚腥、回車、水平制表符和垂直制表符瓶逃,對(duì)應(yīng)的地十六進(jìn)制ASCII分別是:07束铭、1B、0C厢绝、0A契沫、0D、09昔汉、0B

x
字符 x

\\
反斜線字符

\0n
帶有八進(jìn)制值 0 的字符 n (0 <= n <= 7)

\0nn
帶有八進(jìn)制值 0 的字符 nn (0 <= n <= 7)

\0mnn
帶有八進(jìn)制值 0 的字符 mnn(0 <= m <= 3懈万、0 <= n <= 7)

\xhh
帶有十六進(jìn)制值 0x 的字符 hh

\uhhhh
帶有十六進(jìn)制值 0x 的字符 hhhh

\t
制表符 ('\u0009')

\n
新行(換行)符 ('\u000A')

\r
回車符 ('\u000D')

\f
換頁(yè)符 ('\u000C')

\a
報(bào)警 (bell) 符 ('\u0007')

\e
轉(zhuǎn)義符 ('\u001B')

\cx
對(duì)應(yīng)于 x 的控制符

匹配字符類

使用的方括號(hào)[]的表示法被稱作是一個(gè)字符類(character class)。一個(gè)字符類匹配在一個(gè)可能的字符列表中的單個(gè)字符靶病,預(yù)定義字符類

.
任何字符(與行結(jié)束符可能匹配也可能不匹配)

\d
數(shù)字:[0-9]

\D
非數(shù)字: [^0-9]

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

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

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

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

在字符類之外会通,上面的12個(gè)標(biāo)點(diǎn)字符是元字符。在一個(gè)字符類中娄周,只有其中4個(gè)字符擁有特殊功能:\涕侈、^、-和]煤辨。(也就是說(shuō)裳涛,在字符類里面,除了那4個(gè)特殊字符掷酗,其它的字符都不需要使用轉(zhuǎn)義符调违。)如果使用的是Java或者是.NET,那么左方括號(hào)[在字符類也是一個(gè)元字符,所有的其它字符都是字面量泻轰,只是把它們自身加入到了字符類中

點(diǎn)號(hào)是最古老也是最簡(jiǎn)單的正則表達(dá)式特性之一技肩。它的含義永遠(yuǎn)是匹配任意單個(gè)字符。點(diǎn)號(hào)是最經(jīng)常被濫用的正則表達(dá)式特性,最好只有當(dāng)你確實(shí)想要允許出現(xiàn)任意字符是地虚婿,才使用點(diǎn)號(hào)旋奢,而在任何場(chǎng)合,都應(yīng)當(dāng)使用一個(gè)字符類或者是否定字符類來(lái)實(shí)現(xiàn)

在.NET然痊、Java至朗、PCRE、Perl剧浸、Python中锹引,<(?s)>是用于“點(diǎn)號(hào)匹配換行符”模式的模式修飾符

反斜杠總是會(huì)對(duì)緊跟其后的字符進(jìn)行轉(zhuǎn)義,這與它在字符類之外的作用一樣唆香。被轉(zhuǎn)義的字符可以是單個(gè)字符嫌变,也可以是一個(gè)范圍的開始或結(jié)束。另外4個(gè)元字符只有當(dāng)它們被放置在特定位置時(shí)才擁有特殊含義躬它。在使用中總是對(duì)這些元字符進(jìn)行轉(zhuǎn)義會(huì)使你的正則表達(dá)式更加容易讓人理解

[abc]
a腾啥、b 或 c(簡(jiǎn)單類)

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

[a-zA-Z]
a 到 z 或 A 到 Z倘待,兩頭的字母包括在內(nèi)(范圍)

[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](減去)

字母數(shù)字字符則不能使用反斜杠來(lái)轉(zhuǎn)義

如果緊跟著左括號(hào)后面是一個(gè)脫字符(^),那么就會(huì)對(duì)整個(gè)字符類取否锣披。也就是就它會(huì)匹配不屬于該字符類列表中的任意字符贞间。一個(gè)否定字符類會(huì)匹配換行符號(hào)贿条,除非把換行也加入到否定字符類中

連字符(-)被放在兩個(gè)字符之間的時(shí)候就會(huì)創(chuàng)建一個(gè)范圍雹仿。該范圍所組成的字符類包含連字符之前的字符、連字符之后的字符整以,以及按照字母表順序位于這兩個(gè)字符之間的所有字符

<\d>和<[\d]>都會(huì)匹配單個(gè)數(shù)字胧辽,每個(gè)小寫的簡(jiǎn)寫都擁有一個(gè)相關(guān)聯(lián)的大寫簡(jiǎn)定字符,其含義正好相反公黑。因此<\D>會(huì)匹配不是數(shù)字的任意字符邑商,所以同<[^\d]>是等價(jià)的

<\w>會(huì)匹配單個(gè)的單詞字符(word character),所謂的單詞字符指的是能夠出現(xiàn)在一個(gè)單詞中的字符凡蚜,這包括了字母人断、數(shù)字和下劃線。<\W>則會(huì)匹配不屬于上述字符集合中的任意字符朝蜘。在Java恶迈、JavaScript、PCRE和Ruby中谱醇,<\w>總是和<[a-zA-Z0-9_]>的含義完全相同暇仲,而在.NET和Perl中步做,會(huì)包含其它字母表(泰語(yǔ)等)的字母和數(shù)字

<\s>匹配任意的空白字符,其中包括了空格奈附、制表符和換行符全度。在.NET、Perl和JavaScript中斥滤,<\s>也會(huì)匹配杜撰Unicode標(biāo)準(zhǔn)定義這空白號(hào)的字符将鸵。在JavaScript中對(duì)于<\s>使用的是Unicode,對(duì)<\d>和<\w>則使用ASCII標(biāo)準(zhǔn)佑颇。<\S>會(huì)匹配<\s>不能匹配的任意字符

量詞

當(dāng)我們要匹配的正則表達(dá)式里面有一部分重復(fù)多次時(shí)咨堤,比如說(shuō)匹配手機(jī)號(hào)或固話時(shí),我們可以使用量詞來(lái)進(jìn)行匹配固定次數(shù)或不定次數(shù)的重復(fù)

如下面的例子:匹配一個(gè)10位的十進(jìn)制數(shù)漩符,可以使用如下正則表達(dá)式

Matcher m = Pattern.compile("\\d{10}").matcher("0123456789");

while (m.find()) {
    System.out.println(m.group());
}

運(yùn)行結(jié)果為

0123456789

正則表達(dá)式中的數(shù)量詞有Greedy (貪心)量詞一喘、Reluctant(懶惰)量詞和Possessive(占有)量詞三種

首先來(lái)看一個(gè)貪心量詞

X?
X,一次或一次也沒(méi)有

X*
X嗜暴,零次或多次

X+
X凸克,一次或多次

X{n}
X,恰好 n 次

X{n,}
X闷沥,至少 n 次

X{n,m}
X萎战,至少 n 次,但是不超過(guò) m 次

量詞<{n}>,其中n是一個(gè)正整數(shù)舆逃,用來(lái)重復(fù)之前的正則記號(hào)n次

對(duì)于固定次數(shù)的重復(fù)蚂维,使用量詞<{n}>。<{1}>這樣和沒(méi)有任何量詞是等價(jià)的路狮,<ab{1}c>和<abc>是等價(jià)的虫啥,<{0}>是重復(fù)之前的記號(hào)0次,<ab{0}c>和<ac>是同樣的正則表達(dá)式

對(duì)于可變次數(shù)重復(fù)奄妨,我們使用量詞<{n,m}>涂籽,其中n是一個(gè)正整數(shù),并且m大于n,至少 n 次砸抛,但是不超過(guò) m 次评雌。對(duì)于可變次數(shù)重復(fù)的情形,其中所有選擇分析重復(fù)的順序就會(huì)產(chǎn)生影響直焙。如果n和m是相等的景东,那就是固定次數(shù)的重復(fù)

量詞<{n, }>,其中n是一個(gè)正整數(shù)奔誓,支持無(wú)限次數(shù)重復(fù)斤吐。<\d{1,}>匹配一個(gè)或多個(gè)數(shù)字,<\d+>也一樣,在一個(gè)不是量詞的正則記號(hào)之后添加一個(gè)“+”曲初,意味著一次或多次体谒;<\d{0,}>匹配零個(gè)或多個(gè)數(shù)字,<\d>也一樣臼婆,“”意味著0次或多次抒痒。<h?>與<h{0,1}>的效果是一樣的,在一個(gè)合法和完整的非量詞正則記號(hào)之后的“?”意味著0或1次

量詞還可以嵌套颁褂。<(e\d+)?>會(huì)匹配一個(gè)e之后跟著一個(gè)或是多個(gè)數(shù)字故响,或者是一個(gè)長(zhǎng)度為0的匹配

Reluctant(懶惰)量詞和Possessive(占有)量詞與Greedy (貪心)量詞基本語(yǔ)法類似

Reluctant 數(shù)量詞

X??
X,一次或一次也沒(méi)有

X*?
X颁独,零次或多次

X+?
X彩届,一次或多次

X{n}?
X,恰好 n 次

X{n,}?
X誓酒,至少 n 次

X{n,m}?
X樟蠕,至少 n 次,但是不超過(guò) m 次

Possessive 數(shù)量詞

X?+
X靠柑,一次或一次也沒(méi)有

X*+
X寨辩,零次或多次

X++
X,一次或多次

X{n}+
X歼冰,恰好 n 次

X{n,}+
X靡狞,至少 n 次

X{n,m}+
X,至少 n 次隔嫡,但是不超過(guò) m 次

在貪心量詞后面加上一個(gè)問(wèn)號(hào)“?”可以使任何量詞變?yōu)閼卸枇吭~甸怕;同理在貪心量詞后面加上一個(gè)加號(hào)“+”可以使任何量詞變?yōu)檎加辛吭~。下面來(lái)講一下幾種量詞的區(qū)別:

greedy量詞是最常用的腮恩,被看作“貪婪的”梢杭,因?yàn)樗谝淮尉妥x入整個(gè)被模糊匹配的字符串。如果第一個(gè)匹配嘗試(整個(gè)輸入字符串)失敗庆揪,匹配器就會(huì)在被匹配字符串中的最后一位后退 一個(gè)字符并且再次嘗試式曲,重復(fù)這個(gè)過(guò)程妨托,直到找到匹配或者沒(méi)有更多剩下的字符可以后退為止缸榛。根據(jù)表達(dá)式中使用的量詞,它最后試圖匹配的內(nèi)容是1 個(gè)或者0個(gè)字符兰伤。因?yàn)榭偸菑淖畲笃ヅ溟_始匹配内颗,故稱貪婪

reluctant量詞采取相反的方式:它們從被匹配字符串的開頭開始,然后逐步地一次讀取一個(gè)字符搜索匹配敦腔,直到找到匹配或?qū)⒄麄€(gè)字符串吞入均澳。因?yàn)榭偸菑淖钚∑ヅ溟_始,故稱懶惰

possessive量詞總是讀完整個(gè)輸入字符串,嘗試一次(而且只有一次)匹配找前。和greedy量詞不同糟袁,possessive從不后退

貪心量詞會(huì)找到最長(zhǎng)的可能匹配,懶惰量詞則會(huì)找到最短的可能匹配躺盛,兩者都會(huì)進(jìn)行回退项戴,但是占有量詞不進(jìn)行回退

使用如下代碼進(jìn)行驗(yàn)證

System.out.println("Greedy貪心量詞");
Matcher m = Pattern.compile("1.*a").matcher("12a34abc");
while (m.find()) {
    System.out.println(m.group());
}

System.out.println("Reluctant懶惰量詞");
Matcher m1 = Pattern.compile("1.*?a").matcher("12a34abc");
while (m1.find()) {
    System.out.println(m1.group());
}

System.out.println("Possessive占有量詞");
Matcher m2 = Pattern.compile("1.*+a").matcher("12a34abc");
while (m2.find()) {
    System.out.println(m2.group());
}

得到的結(jié)果為

Greedy貪心量詞
12a34a
Reluctant懶惰量詞
12a
Possessive占有量詞

分組與邊界匹配器

首先我們來(lái)看一個(gè)問(wèn)題,匹配My cat is brown中的cat槽惫,但是不會(huì)匹配category或是bobcat周叮,看下面的正則表達(dá)式

Matcher m = Pattern.compile("\\bcat\\b").matcher("My cat is brown");

while (m.find()) {
    System.out.println(m.group());
}

運(yùn)行結(jié)果為

cat

在上面的正則表達(dá)式里面,我們使用到了單詞邊界匹配器

^
行的開頭

$
行的結(jié)尾

\b
單詞邊界

\B
非單詞邊界

\A
輸入的開頭

\G
上一個(gè)匹配的結(jié)尾

\Z
輸入的結(jié)尾界斜,僅用于最后的結(jié)束符(如果有的話)

\z
輸入的結(jié)尾

正則表達(dá)式記號(hào)<\b>被稱作是一個(gè)單詞邊界仿耽,它會(huì)匹配一個(gè)單詞的開始或結(jié)束,就它自身而言各薇,所產(chǎn)生的一個(gè)長(zhǎng)度為0的匹配项贺。

嚴(yán)格來(lái)講,<\b>會(huì)匹配如下3種位置:

  • 在目標(biāo)文本的第一個(gè)字符之前峭判,如果第一個(gè)字符是單詞字符

  • 在目標(biāo)文本的最后一個(gè)字符之后敬扛,如果最后一個(gè)字符是單詞字符

  • 在目標(biāo)文本的兩個(gè)字符之間,其中一個(gè)是單詞字符朝抖,而另外一個(gè)不是單詞字符

<\B>會(huì)匹配在目標(biāo)文本中的<\b>不匹配的第一個(gè)位置啥箭。換句話說(shuō),<\B>會(huì)匹配不屬于單詞開始或結(jié)束的每一個(gè)位置治宣。

單詞字符就是可以在單詞中出現(xiàn)的字符急侥。

JavaScript、PCRE和Ruby只把ASCII字符看做是單詞字符侮邀。<\w>因此與<[a-zA-z0-9]>是完全等同的坏怪;.NET和Perl把所有語(yǔ)言字母表中的字母和數(shù)字都當(dāng)作單詞字符;Python則為你提供了一個(gè)選項(xiàng)绊茧,只有在創(chuàng)建正則表達(dá)式時(shí)傳遞了UNICODE或是U選項(xiàng)铝宵,非ASCII的字符才會(huì)被包括起來(lái);Java則表現(xiàn)得不是很一致华畏,<\w>只匹配ASCII字符鹏秋,但是<\b>則是支持Unicode的,因此可以支持任何字母表亡笑。

正則表達(dá)式中的記號(hào)<^>,<$>,<\A>,<\Z>和<\z>被稱為定位符(anchor)侣夷,它們并不匹配任意字符。事實(shí)上仑乌,它們匹配的特定的位置百拓,也就是說(shuō)把正則表達(dá)式這些位置來(lái)進(jìn)行匹配琴锭。

JavaScript不支持<\A>。定位符<>和<\A>是等價(jià)的衙传,前提是不能打開“和$匹配換行處”這個(gè)選項(xiàng)决帖。對(duì)于除了Ruby之外的所有其它正則表達(dá)式流派來(lái)說(shuō),該選項(xiàng)都是默認(rèn)關(guān)閉的蓖捶。除非使用JavaScript古瓤,一般都推薦使用<\A>。<\A>的含義問(wèn)題保持不變的腺阳,因此可以避免由于正則選項(xiàng)設(shè)置而造成的混淆或錯(cuò)誤落君。

.NET、Java亭引、PCRE绎速、Perl、Ruby同時(shí)支持<\Z>和<\z>焙蚓,Python只支持<\Z>纹冤,JavaScript則根本不提供對(duì)<\Z>和<\z>的支持。<\Z>和<\z>的唯一區(qū)別是當(dāng)目標(biāo)文本的最后一個(gè)字符是換行符的時(shí)候购公,在這種情形下萌京,<\Z>可以匹配到目標(biāo)文本的最結(jié)尾處,也就是在最后的換行符之后 的位置宏浩,同時(shí)也可以匹配緊跟這個(gè)換行符之前的位置知残;<\z>則只會(huì)匹配目標(biāo)文本的最末尾處,因此如果存在一個(gè)多余的換行符比庄,那么它無(wú)法匹配求妹。

定位符<>和<\Z>是等價(jià)的,前提是不能打開“^和匹配換行處”這個(gè)選項(xiàng)佳窑。對(duì)于除了Ruby之外的所有其它正則表達(dá)式流派來(lái)說(shuō)制恍,該選項(xiàng)都是默認(rèn)關(guān)閉的

邏輯運(yùn)算符

當(dāng)匹配多個(gè)選擇分支時(shí),如匹配Mary,Jane and Sue went to Mary’s house中的Mary,Jane或Sue神凑,使用的正則表達(dá)式為

Matcher m = Pattern.compile("Mary|Jane|Sue").matcher("Mary,Jane and Sue went to Mary’s house ");
while (m.find()) {
    System.out.println(m.group());
}

執(zhí)行結(jié)果為

Mary

Jane

Sue

Mary

豎線净神,或是稱作管道符號(hào),會(huì)把正則表達(dá)式拆分成多個(gè)選擇分支溉委,每個(gè)只會(huì)匹配一個(gè)名字鹃唯,但是每次卻可以匹配不同的名字

正則表達(dá)式里面的邏輯運(yùn)算符如下表表示

XY
X  后跟 Y

X|Y
X  或 Y

(X)
X,作為捕獲組

上面的正則表達(dá)式還有以下問(wèn)題:在匹配的過(guò)程中會(huì)匹配DJanet中的Jane薛躬。如下面的的正則表達(dá)式所示

Matcher m = Pattern.compile("Mary|Jane|Sue").matcher("Mary,Jane and Sue went to Mary’s house DJanet");

while (m.find()) {
    System.out.println(m.group());
}

執(zhí)行結(jié)果為

Mary

Jane

Sue

Mary

Jane

這個(gè)時(shí)候俯渤,可能會(huì)想到之前使用到的單詞邊界匹配器,把正則表達(dá)式修改一下型宝,添加單詞邊界匹配

Matcher m = Pattern.compile("\\bMary|Jane|Sue\\b").matcher("Mary,Jane and Sue went to Mary’s house DJanet");

while (m.find()) {
    System.out.println(m.group());
}

執(zhí)行結(jié)果為

Mary

Jane

Sue

Mary

Jane

執(zhí)行結(jié)果有也不是我們想要的答案八匠,上面的正則表達(dá)式寫法上面有問(wèn)題,應(yīng)該寫成下面這樣

Matcher m = Pattern.compile("\\bMary\\b|\\bJane\\b|\\b Sue\\b").matcher("Mary,Jane and Sue went to Mary’s house DJanet");

“|”在所有正則操作符中擁有最低的優(yōu)先級(jí)趴酣。如果想要正則表達(dá)式中的一些內(nèi)容不受替代操作影響的話梨树,那么就需要把這些選擇分支進(jìn)行分組,分組是通過(guò)圓括號(hào)來(lái)實(shí)現(xiàn)的岖寞,括號(hào)擁有在所有正則操作符中的最高優(yōu)先級(jí)

Matcher m = Pattern.compile("\\b(Mary|Jane|Sue)\\b").matcher("Mary,Jane and Sue went to Mary’s house DJanet");

while (m.find()) {
    System.out.println(m.group());
}

執(zhí)行結(jié)果為

Mary

Jane

Sue

Mary

一組圓括號(hào)不僅僅是一個(gè)分組抡四,它還是一個(gè)捕獲分組,正則表達(dá)式\b(\d\d\d\d)-(\d\d)-(\d\d)\b擁有三個(gè)捕獲分組仗谆,分組是按照左括號(hào)的順序從左到右進(jìn)行編號(hào)的指巡,(\d\d\d\d)、(\d\d)隶垮、(\d\d)分別為3個(gè)分組

分組分為捕獲性分組和非捕獲性分組藻雪,簡(jiǎn)單的說(shuō)捕獲性分組就是捕獲分組所匹配的內(nèi)容暫且存儲(chǔ)在某個(gè)地方,以便下次使用狸吞,捕獲性分組以(...)表示,有些地方將取得捕獲性分組所匹配結(jié)果的過(guò)程稱之為"反向引用",非捕獲性分組不捕獲分組所匹配的內(nèi)容勉耀,當(dāng)然也就得不到匹配的結(jié)果,非捕獲性分組以(?:...)表示,在一些只需要分組匹配但是并不需要得到各個(gè)分組匹配的結(jié)果時(shí)蹋偏,使用非捕獲性分組可以提高匹配速度

在匹配過(guò)程中便斥,當(dāng)正則表達(dá)式引擎到達(dá)右括號(hào)而退出分組的時(shí)候,它會(huì)把該捕獲分組所匹配到的文本的子串存儲(chǔ)起來(lái)威始。當(dāng)我們匹配2008-08-05時(shí)枢纠,2008被保存到第一個(gè)捕獲中,08在第2個(gè)捕獲中黎棠,而05則在第3個(gè)捕獲中

使用\b\d\d(\d\d)-\1-\1\b可以匹配像2008-08-08這樣的日期(年減去世紀(jì)京郑、月份和該月的天數(shù)都是相同的數(shù)字),在這個(gè)正則表達(dá)式中葫掉,我們使用反向引用來(lái)在該正則表達(dá)式中的任何地方匹配相同的文本些举。可以使用反斜杠之后跟一個(gè)單個(gè)數(shù)字(19)來(lái)引用前9個(gè)捕獲分組俭厚,而第(1099)則要使用\10~\99

注意户魏,不要使用\01。它或者是一個(gè)八進(jìn)制的轉(zhuǎn)義挪挤,或者會(huì)產(chǎn)生一個(gè)錯(cuò)誤叼丑。在JavaScript中此正則表達(dá)式還會(huì)匹配12—34。因?yàn)樵贘avaScript中扛门,對(duì)一個(gè)還沒(méi)有參與匹配的分組的反向引用總是會(huì)匹配成功鸠信,這同捕獲了長(zhǎng)度為0的匹配的分組的反向引用是一樣的

特殊字符

^
匹配輸入字符串開始處的位置,但在中括號(hào)表達(dá)式中使用的情況除外论寨,在那種情況下它對(duì)字符集求反星立。若要匹配 ^ 字符本身爽茴,請(qǐng)使用 \^

$
匹配輸入字符串結(jié)尾的位置。如果設(shè)置了 RegExp 對(duì)象的 Multiline 屬性绰垂,那么 $ 還匹配 \n 或 \r 前面的位置室奏。若要匹配 $ 字符本身,請(qǐng)使用 \$

( )
標(biāo)記子表達(dá)式的開始和結(jié)束劲装‰誓可以捕獲子表達(dá)式以供以后使用。若要匹配這兩個(gè)字符占业,請(qǐng)使用 \( 和 \)

*
零次或多次匹配前面的字符或子表達(dá)式绒怨。若要匹配 * 字符,請(qǐng)使用 \*

+
一次或多次匹配前面的字符或子表達(dá)式谦疾。若要匹配 + 字符南蹂,請(qǐng)使用 \+

.
匹配除換行符 \n 之外的任何單個(gè)字符。若要匹配 .餐蔬,請(qǐng)使用 \.

[ ]
標(biāo)記中括號(hào)表達(dá)式的開始碎紊。若要匹配這些字符,請(qǐng)使用 \[ 和 \]

?
零次或一次匹配前面的字符或子表達(dá)式樊诺,或指示“非貪心”限定符仗考。若要匹配 ? 字符,請(qǐng)使用 \?

\
將下一字符標(biāo)記為特殊字符词爬、文本秃嗜、反向引用或八進(jìn)制轉(zhuǎn)義符。例如顿膨,字符 n 匹配字符 n锅锨。\n 匹配換行符。序列 \\ 匹配 \恋沃,序列 \( 匹配 (

/
表示文本正則表達(dá)式的開始或結(jié)束必搞。若要匹配 / 字符,請(qǐng)使用 \/

{ }
標(biāo)記限定符表達(dá)式的開始囊咏。若要匹配這些字符恕洲,請(qǐng)使用 \{ 和 \}

|
指出在兩個(gè)項(xiàng)之間進(jìn)行選擇。要匹配 |梅割,請(qǐng)使用 \|

優(yōu)先級(jí)

\
轉(zhuǎn)義符

(), (?:), (?=), []
括號(hào)和中括號(hào)

*, +, ?, {n}, {n,}, {n,m}
限定符

^, $, \任何元字符霜第、任何字符
定位點(diǎn)和序列

|
替換

匹配

//String類中的匹配
public boolean matches(String regex)

//Pattern類中的匹配
public static boolean matches(String regex, CharSequence input)

切割

//普通切割,如果沒(méi)有匹配的則返回第一條數(shù)據(jù)户辞,為原來(lái)的數(shù)據(jù)
public String[] split(String regex)

//切割并限制個(gè)數(shù)
public String[] split(String regex, int limit)

替換

//替換匹配到的第一次
public String replaceFirst(String regex, String replacement)

//替換匹配的全部?jī)?nèi)容
public String replaceAll(String regex, String replacement)

獲取

需要用到Pattern和Matcher類泌类,將規(guī)則封裝成表達(dá)式

Pattern pattern = Pattern.compile(String regex);

根據(jù)字符串獲取表達(dá)式的匹配器對(duì)象

Matcher matcher = pattern.matcher(CharSequence input);

進(jìn)行查找,與迭代器的模式相似

while (matcher.find()) {
    System.out.println("獲取匹配到的內(nèi)容" + matcher.group());
    System.out.println("該內(nèi)容在字符串中的起始位置" + matcher.start());
    System.out.println("該內(nèi)容在字符串中的結(jié)束位置" + matcher.end());
}

占位符

首先看一個(gè)案例

String regex1 = "(.{1})(\\d{2})";

System.out.println("18123241314520"
        .replaceAll(regex1, "$1----$2    "));

//輸出
1----81    2----32    4----13    1----45    20

n用來(lái)匹配表達(dá)式中第n個(gè)()里的內(nèi)容底燎,1代表(.{1})匹配的內(nèi)容刃榨,$2代表(\d{2})匹配的內(nèi)容

匹配中文

Java中要匹配中文的正則表達(dá)式可以有兩種寫法:一是使用unicode中文碼弹砚;二是直接使用漢字字符

[u4E00-u9FA5]漢字

[^x00-xff]雙字節(jié)字符

[uFE30-uFFA0]全角字符

常用的正則表達(dá)式

網(wǎng)址(URL)
[a-zA-z]+://[^\s]*

IP地址(IP Address)
((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)

電子郵件(Email)
\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*

QQ號(hào)碼
[1-9]\d{4,}

HTML標(biāo)記(包含內(nèi)容或自閉合)
<(.*)(.*)>.*<\/\1>|<(.*) \/>

密碼(由數(shù)字/大寫字母/小寫字母/標(biāo)點(diǎn)符號(hào)組成,四種都必有喇澡,8位以上)
(?=^.{8,}$)(?=.*\d)(?=.*\W+)(?=.*[A-Z])(?=.*[a-z])(?!.*\n).*$

日期(年-月-日)
(\d{4}|\d{2})-((0?([1-9]))|(1[1|2]))-((0?[1-9])|([12]([1-9]))|(3[0|1]))

日期(月/日/年)
((0?[1-9]{1})|(1[1|2]))/(0?[1-9]|([12][1-9])|(3[0|1]))/(\d{4}|\d{2})

時(shí)間(小時(shí):分鐘, 24小時(shí)制)
((1|0?)[0-9]|2[0-3]):([0-5][0-9])

漢字(字符)
[\u4e00-\u9fa5]

中文及全角標(biāo)點(diǎn)符號(hào)(字符)
[\u3000-\u301e\ufe10-\ufe19\ufe30-\ufe44\ufe50-\ufe6b\uff01-\uffee]

中國(guó)大陸固定電話號(hào)碼
(\d{4}-|\d{3}-)?(\d{8}|\d{7})

中國(guó)大陸手機(jī)號(hào)碼
1[356789]\d{9}

中國(guó)大陸郵政編碼
[1-9]\d{5}

中國(guó)大陸身份證號(hào)(15位或18位)
\d{15}(\d\d[0-9xX])?

非負(fù)整數(shù)(正整數(shù)或零)
\d+

正整數(shù)
[0-9]*[1-9][0-9]*

負(fù)整數(shù)
-[0-9]*[1-9][0-9]*

整數(shù)
-?\d+

小數(shù)
(-?\d+)(\.\d+)?
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末迅栅,一起剝皮案震驚了整個(gè)濱河市殊校,隨后出現(xiàn)的幾起案子晴玖,更是在濱河造成了極大的恐慌,老刑警劉巖为流,帶你破解...
    沈念sama閱讀 211,561評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件呕屎,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡敬察,警方通過(guò)查閱死者的電腦和手機(jī)秀睛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)莲祸,“玉大人蹂安,你說(shuō)我怎么就攤上這事∪裰模” “怎么了田盈?”我有些...
    開封第一講書人閱讀 157,162評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)缴阎。 經(jīng)常有香客問(wèn)我允瞧,道長(zhǎng),這世上最難降的妖魔是什么蛮拔? 我笑而不...
    開封第一講書人閱讀 56,470評(píng)論 1 283
  • 正文 為了忘掉前任述暂,我火速辦了婚禮,結(jié)果婚禮上建炫,老公的妹妹穿的比我還像新娘畦韭。我一直安慰自己,他們只是感情好肛跌,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評(píng)論 6 385
  • 文/花漫 我一把揭開白布艺配。 她就那樣靜靜地躺著,像睡著了一般惋砂。 火紅的嫁衣襯著肌膚如雪妒挎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,806評(píng)論 1 290
  • 那天西饵,我揣著相機(jī)與錄音酝掩,去河邊找鬼。 笑死眷柔,一個(gè)胖子當(dāng)著我的面吹牛期虾,可吹牛的內(nèi)容都是我干的原朝。 我是一名探鬼主播,決...
    沈念sama閱讀 38,951評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼镶苞,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼喳坠!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起茂蚓,我...
    開封第一講書人閱讀 37,712評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤壕鹉,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后聋涨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晾浴,經(jīng)...
    沈念sama閱讀 44,166評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評(píng)論 2 327
  • 正文 我和宋清朗相戀三年牍白,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了脊凰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,643評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡茂腥,死狀恐怖狸涌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情最岗,我是刑警寧澤帕胆,帶...
    沈念sama閱讀 34,306評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站仑性,受9級(jí)特大地震影響惶楼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜诊杆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評(píng)論 3 313
  • 文/蒙蒙 一歼捐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧晨汹,春花似錦豹储、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至铝穷,卻和暖如春钠怯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背曙聂。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工晦炊, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,351評(píng)論 2 360
  • 正文 我出身青樓断国,卻偏偏與公主長(zhǎng)得像贤姆,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子稳衬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容