正則表達(dá)式

簡(jiǎn)介

正則表達(dá)式是由普通字符(例如字符 a 到 z)以及特殊字符(稱為"元字符")組成的文字模式。模式描述在搜索文本時(shí)要匹配的一個(gè)或多個(gè)字符串。正則表達(dá)式作為一個(gè)模板,將某個(gè)字符模式與所搜索的字符串進(jìn)行匹配。

非打印字符

\cx 匹配由x指明的控制字符。例如, \cM 匹配一個(gè) Control-M 或回車(chē)符。x 的值必須為 A-Z 或 a-z 之一。否則,將 c 視為一個(gè)原義的 'c' 字符。
\f 匹配一個(gè)換頁(yè)符。等價(jià)于 \x0c 和 \cL。
\n 匹配一個(gè)換行符。等價(jià)于 \x0a 和 \cJ。
\r 匹配一個(gè)回車(chē)符。等價(jià)于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、換頁(yè)符等等。等價(jià)于 [ \f\n\r\t\v]。
\S 匹配任何非空白字符。等價(jià)于 [^ \f\n\r\t\v]。
\t 匹配一個(gè)制表符。等價(jià)于 \x09 和 \cI。
\v 匹配一個(gè)垂直制表符。等價(jià)于 \x0b 和 \cK。

特殊字符

$ 匹配輸入字符串的結(jié)尾位置。如果設(shè)置了 RegExp 對(duì)象的 Multiline 屬性,則 $ 也匹配 '\n' 或 '\r'。要匹配 $ 字符本身,請(qǐng)使用 \$。
( ) 標(biāo)記一個(gè)子表達(dá)式的開(kāi)始和結(jié)束位置。子表達(dá)式可以獲取供以后使用。要匹配這些字符,請(qǐng)使用 \( 和\ )。
\匹配前面的子表達(dá)式零次或多次。要匹配 * 字符,請(qǐng)使用 \*。
+匹配前面的子表達(dá)式一次或多次。要匹配 + 字符,請(qǐng)使用\ +。
. 匹配除換行符 \n 之外的任何單字符。要匹配 . ,請(qǐng)使用\ . 。
[ 標(biāo)記一個(gè)中括號(hào)表達(dá)式的開(kāi)始。要匹配 [,請(qǐng)使用\ [。
? 匹配前面的子表達(dá)式零次或一次,或指明一個(gè)非貪婪限定符。要匹配 ? 字符,請(qǐng)使用 \?。
\ 將下一個(gè)字符標(biāo)記為或特殊字符、或原義字符、或向后引用、或八進(jìn)制轉(zhuǎn)義符。例如, 'n' 匹配字符 'n'。'\n' 匹配換行符。序列 '\' 匹配 "",而 '\(' 則匹配 "("。
^ 匹配輸入字符串的開(kāi)始位置,除非在方括號(hào)表達(dá)式中使用,此時(shí)它表示不接受該字符集合。要匹配 ^ 字符本身,請(qǐng)使用 \^。
{ 標(biāo)記限定符表達(dá)式的開(kāi)始。要匹配 {,請(qǐng)使用 \{。
| 指明兩項(xiàng)之間的一個(gè)選擇。要匹配 |,請(qǐng)使用 \|。

量詞和限定符

* (貪婪)匹配前面的子表達(dá)式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等價(jià)于{0,}。
+(懶惰)匹配前面的子表達(dá)式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等價(jià)于 {1,}。
?(占有) 匹配前面的子表達(dá)式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的 "does" 或 "doxy" 中的 "do" 。? 等價(jià)于 {0,1}。
{n} n 是一個(gè)非負(fù)整數(shù)。匹配確定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的兩個(gè) o。
{n,} n 是一個(gè)非負(fù)整數(shù)。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等價(jià)于 'o+'。'o{0,}' 則等價(jià)于 'o'。
{n,m} m 和 n 均為非負(fù)整數(shù),其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 將匹配 "fooooood" 中的前三個(gè) o。'o{0,1}' 等價(jià)于 'o?'。請(qǐng)注意在逗號(hào)和兩個(gè)數(shù)之間不能有空格。
*? 重復(fù)任意次,但盡可能少重復(fù)
如 "acbacb" 正則 "a.
?b" 只會(huì)取到第一個(gè)"acb" 原本可以全部取到但加了限定符后,只會(huì)匹配盡可能少的字符 ,而"acbacb"最少字符的結(jié)果就是"acb"
+? 重復(fù)1次或更多次,但盡可能少重復(fù), 與上面一樣,只是至少要重復(fù)1次
?? 重復(fù)0次或1次,但盡可能少重復(fù) 如 "aaacb" 正則 "a.??b" 只會(huì)取到最后的三個(gè)字符"acb"
{n,m}? 重復(fù)n到m次,但盡可能少重復(fù),如 "aaaaaaaa" 正則 "a{0,m}" 因?yàn)樽钌偈?次所以取到結(jié)果為空
{n,}? 重復(fù)n次以上,但盡可能少重復(fù),如 "aaaaaaa" 正則 "a{1,}" 最少是1次所以取到結(jié)果為 "a

元字符

"^" :^會(huì)匹配行或者字符串的起始位置,有時(shí)還會(huì)匹配整個(gè)文檔的起始位置。

"$" :$會(huì)匹配行或字符串的結(jié)尾

"\b" :不會(huì)消耗任何字符只匹配單詞邊界,也就是指單詞和空格間的位置,常用于匹配單詞邊界 如 我想從字符串中"This is Regex"匹配單獨(dú)的單詞 "is" 正則就要寫(xiě)成 "\bis\b

"\d": 匹配數(shù)字,
例如要匹配一個(gè)固定格式的電話號(hào)碼以0開(kāi)頭前4位后7位,如0737-5686123 正則:^0\d\d\d-\d\d\d\d\d\d\d$

"\w":匹配字母,數(shù)字,下劃線.
例如我要匹配"a2345BCD__TTz" 正則:"\w+" 這里的"+"字符為一個(gè)量詞指重復(fù)的次數(shù),等價(jià)于'[A-Za-z0-9_]'。

"\W"
匹配任何非單詞字符。等價(jià)于 '[^A-Za-z0-9_]'。

"\s":匹配空格
例如字符 "a b c" 正則:"\w\s\w\s\w" 一個(gè)字符后跟一個(gè)空格,如有字符間有多個(gè)空格直接把"\s" 寫(xiě)成 "\s+" 讓空格重復(fù)

".":匹配除了換行符以外的任何字符
這個(gè)算是"\w"的加強(qiáng)版了"\w"不能匹配 空格 如果把字符串加上空格用"\w"就受限了,看下用 "."是如何匹配字符"a23 4 5 B C D__TTz" 正則:".+"

"[abc]": 字符組 匹配包含括號(hào)內(nèi)元素的字符
這個(gè)比較簡(jiǎn)單了只匹配括號(hào)內(nèi)存在的字符,還可以寫(xiě)成[a-z]匹配a至z的所以字母就等于可以用來(lái)控制只能輸入英文了

"[^xyz]"
負(fù)值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'、'l'、'i'、'n'

捕獲組和反向引用

什么是捕獲組

捕獲組就是把正則表達(dá)式中子表達(dá)式匹配的內(nèi)容,保存到內(nèi)存中以數(shù)字編號(hào)或顯式命名的組里,方便后面引用。當(dāng)然,這種引用既可以是在正則表達(dá)式內(nèi)部,也可以是在正則表達(dá)式外部。

捕獲組有兩種形式,一種是普通捕獲組,另一種是命名捕獲組,通常所說(shuō)的捕獲組指的是普通捕獲組。語(yǔ)法如下:
普通捕獲組:(Expression)
命名捕獲組:(?<name>Expression)

什么是反向引用

反向引用匹配原理

捕獲組(Expression)在匹配成功時(shí),會(huì)將子表達(dá)式匹配到的內(nèi)容,保存到內(nèi)存中一個(gè)以數(shù)字編號(hào)的組里,可以簡(jiǎn)單的認(rèn)為是對(duì)一個(gè)局部變量進(jìn)行了賦值,這時(shí)就可以通過(guò)反向引用方式,引用這個(gè)局部變量的值。一個(gè)捕獲組(Expression)在匹配成功之前,它的內(nèi)容可以是不確定的,一旦匹配成功,它的內(nèi)容就確定了,反向引用的內(nèi)容也就是確定的了。

反向引用必然要與捕獲組一同使用的,如果沒(méi)有捕獲組,而使用了反向引用的語(yǔ)法,不同語(yǔ)言的處理方式不一致,有的語(yǔ)言會(huì)拋異常,有的語(yǔ)言會(huì)當(dāng)作普通的轉(zhuǎn)義處理。

一個(gè)正則表達(dá)式模式或部分模式兩邊添加圓括號(hào)將導(dǎo)致相關(guān)匹配存儲(chǔ)到一個(gè)臨時(shí)緩沖區(qū)中,所捕獲的每個(gè)子匹配都按照在正則表達(dá)式模式中從左到右出現(xiàn)的順序存儲(chǔ)。緩沖區(qū)編號(hào)從 1 開(kāi)始,最多可存儲(chǔ) 99 個(gè)捕獲的子表達(dá)式。每個(gè)緩沖區(qū)都可以使用 \n 訪問(wèn),其中 n 為一個(gè)標(biāo)識(shí)特定緩沖區(qū)的一位或兩位十進(jìn)制數(shù)??梢允褂梅遣东@元字符 ?:、?= 或 ?! 來(lái)重寫(xiě)捕獲,忽略對(duì)相關(guān)匹配的保存

其中 ?: 是非捕獲元之一,還有兩個(gè)非捕獲元是 ?= 和 ?!,這兩個(gè)還有更多的含義,前者為正向預(yù)查,在任何開(kāi)始匹配圓括號(hào)內(nèi)的正則表達(dá)式模式的位置來(lái)匹配搜索字符串,后者為負(fù)向預(yù)查,在任何開(kāi)始不匹配該正則表達(dá)式模式的位置來(lái)匹配搜索字符串。

簡(jiǎn)單例子

源字符串:abcdebbcde

正則表達(dá)式:([ab])\1

對(duì)于正則表達(dá)式“([ab])\1”,捕獲組中的子表達(dá)式“[ab]”雖然可以匹配“a”或者“b”,但是捕獲組一旦匹配成功,反向引用的內(nèi)容也就確定了。如果捕獲組匹配到“a”,那么反向引用也就只能匹配“a”,同理,如果捕獲組匹配到的是“b”,那么反向引用也就只能匹配“b”。由于后面反向引用“\1”的限制,要求必須是兩個(gè)相同的字符,在這里也就是“aa”或者“bb”才能匹配成功

考察一下這個(gè)正則表達(dá)式的匹配過(guò)程,在位置0處,由“([ab])”匹配“a”成功,將捕獲的內(nèi)容保存在編號(hào)為1的組中,然后把控制權(quán)交給“\1”,由于此時(shí)捕獲組已記錄了捕獲內(nèi)容為“a”,“\1”也就確定只有匹配到“a”才能匹配成功,這里顯然不滿足,“\1”匹配失敗,由于沒(méi)有可供回溯的狀態(tài),整個(gè)表達(dá)式在位置0處匹配失敗。

正則引擎向前傳動(dòng),在位置5之前,“([ab])”一直匹配失敗。傳動(dòng)到位置5處時(shí),,“([ab])”匹配到“b”,匹配成功,將捕獲的內(nèi)容保存在編號(hào)為1的組中,然后把控制權(quán)交給“\1”,由于此時(shí)捕獲組已記錄了捕獲內(nèi)容為“b”,“\1”也就確定只有匹配到“b”才能匹配成功,滿足條件,“\1”匹配成功,整個(gè)表達(dá)式匹配成功,匹配結(jié)果為“bb”,匹配開(kāi)始位置為5,結(jié)束位置為7。

擴(kuò)展一下,正則表達(dá)式“([a-z])\1{2}”也就表達(dá)連續(xù)三個(gè)相同的小寫(xiě)字母。

復(fù)雜例子

源字符串:aaa bbbb ffffff 999999999

正則表達(dá)式:(\w)((?=\1\1\1)(\1))+

正則表達(dá)式(\w)((?=\1\1\1)(\1))+從匹配結(jié)果上分析,其實(shí)就等價(jià)于 (\w)(\1)*(?=\1\1\1)(\1),因?yàn)椤?”等價(jià)于“{1,}”,表示至少匹配1次,如果最后一個(gè)“((?=\1\1\1)(\1))”匹配成功,那么中間的“((?=\1\1\1)(\1))”一定可以匹配成功,所以中間的限制條件(?=\1\1\1)就沒(méi)有意義了,這時(shí)就可以簡(jiǎn)寫(xiě)為“(\1)”
可以歸納為等價(jià)于

(\w)(\1)*((?=\1\1\1)(\1))

因?yàn)椤?(?=\1\1\1)(\1))”開(kāi)始和結(jié)尾的()原來(lái)是用作量詞+修飾范圍的,這里已經(jīng)沒(méi)有什么意義了,所以表達(dá)式最后可以歸納為等價(jià)于

(\w)(\1)*(?=\1\1\1)(\1)

分析這個(gè)表達(dá)式就容易多了?!?\w)”匹配一個(gè)字符,占一位,“\1”是對(duì)“\w”匹配內(nèi)容的引用,“(\1)*”可以匹配0到無(wú)窮多個(gè)“(\w)”匹配到的字符,“(?=\1\1\1)(\1)”只占一位,但是“(?=\1\1\1)”要求所在位置右側(cè)有三個(gè)連續(xù)相同的“(\w)”匹配到的字符,所以在“(?=\1\1\1)”這個(gè)位置右側(cè)應(yīng)該有三個(gè)字符,不過(guò)只有這個(gè)位置右側(cè)的一個(gè)字符計(jì)入最后的匹配結(jié)果,最后兩個(gè)只作為限制條件,不計(jì)入最后的匹配結(jié)果 。

以“999999999”為例,第一個(gè)“9”由“(\w)”匹配,第二到第六個(gè)“9”由“(\1)*”來(lái)匹配,第七個(gè)“9”由“(?=\1\1\1)(\1)”中最后的“(\1)”來(lái)匹配,而第七、八、九這三個(gè)“9”是用來(lái)保證滿足“(?=\1\1\1)”這個(gè)條件的。

常見(jiàn)應(yīng)用軟件和編程語(yǔ)言對(duì)正則表達(dá)式的支持匯總?cè)缦拢?/h2>

A.1 grep

grep是一種用來(lái)對(duì)文件或標(biāo)準(zhǔn)輸入文本進(jìn)行文字搜索的Unix工具,支持基本、擴(kuò)展和Perl正則表達(dá)式。

-E:使用擴(kuò)展正則表達(dá)式

-G:使用基本正則表達(dá)式

-P:使用Perl正則表達(dá)式

注意事項(xiàng):

①默認(rèn)情況下,grep將把包含著匹配的各個(gè)文本全部顯示,如果只想查看匹配結(jié)果,請(qǐng)使用-o選項(xiàng);

②使用-v選項(xiàng)將對(duì)整個(gè)操作匹配操作進(jìn)行求非————只顯示不匹配的文本行;

③使用-c選項(xiàng)只顯示匹配的總數(shù)而不是此次匹配的細(xì)節(jié);

④grep工具只能進(jìn)行搜索操作,不能進(jìn)行替換操作;

A.2 javascript

javascript 1.x版本在string和RegExp對(duì)象的以下幾個(gè)方法里實(shí)現(xiàn)了正則表達(dá)式處理。
exec:一個(gè)用來(lái)搜索一個(gè)匹配的RegExp方法
match:一個(gè)用來(lái)匹配一個(gè)字符串的string方法
replace:一個(gè)用來(lái)完成替換操作的string方法
search:一個(gè)用來(lái)測(cè)試在某給定字符串里是否存在著一個(gè)匹配的string方法
split:一個(gè)用來(lái)把一個(gè)字符串拆分為多個(gè)子串的string方法
test:一個(gè)用來(lái)測(cè)試在某給定字符串里是否存在著一個(gè)匹配的RegExp方法
△JavaScript度對(duì)正則表達(dá)式的支持源自Perl語(yǔ)言。
注意事項(xiàng):
①JavaScript使用命令行選項(xiàng)來(lái)管理全局的區(qū)分大小寫(xiě)搜索,g選項(xiàng)激活全局搜索功能,i選項(xiàng)讓匹配操作不區(qū)分字母大小寫(xiě),這兩個(gè)選項(xiàng)可組合為gi;
②其他命令行選項(xiàng)包括:m,支持多行字符串;s,支持單行字符串;x,忽略正則表達(dá)式模式里的空白字符;
③在使用回溯引用時(shí),'將返回被匹配字符串前面的所有東西,`將返回被匹配字符串后面的所有東西;+將返回最后一個(gè)被匹配的子表達(dá)式,&將返回被匹配到的所有東西
④JavaScript提供一個(gè)名為RegExp的全局對(duì)象,在執(zhí)行完一個(gè)正則表達(dá)式后,可以通過(guò)這個(gè)對(duì)象獲得與這次執(zhí)行有關(guān)的信息;

⑤JavaScript不支持POSIX字符類;

⑥JavaScript不支持\A和\Z。

A.3 MySQL

MySQL對(duì)正則表達(dá)式的支持體現(xiàn)在允許在where字句里使用如下格式的表達(dá)式:

REGEXP "erpression"

下面是一條使用了正則表達(dá)式的MySQL語(yǔ)句的完整語(yǔ)法:

select * from table where REGEXP 'pattern';

MySQL正則表達(dá)式支持很有用,功能也很強(qiáng)大,但它還算不上是一個(gè)完備的正則表達(dá)式表現(xiàn);以下是它的不足之處:

①只提供搜索支持,不支持使用正則表達(dá)式進(jìn)行替換操作;

②默認(rèn)情況下,正則表達(dá)式搜索不區(qū)分字母的大小寫(xiě);如果需要區(qū)分大小寫(xiě),必須再增加一個(gè)BINARY關(guān)鍵字(放在REGEXP和模式之間);

③用[[:<:]]來(lái)匹配一個(gè)單詞的開(kāi)頭,用[[:>:]]來(lái)匹配一個(gè)單詞的結(jié)束;

④不支持向前預(yù)測(cè);

⑤不支持嵌入條件;

⑥不支持八進(jìn)制字符搜素;

⑦不支持\a、\b、\e、\f和\v;

⑧不支持回溯引用;

A.4 Perl

Perl可以說(shuō)是各種正則表達(dá)式的“祖宗”,各種實(shí)現(xiàn)幾乎斗魚(yú)Perl兼容,正則表達(dá)式是Perl的核心組件之一,如果需要在Perl腳本里使用正則表達(dá)式,只需如下
給出一個(gè)操作和相應(yīng)模式即可:
①m/pattern:匹配給定的模式;
②s/pattern/pattern:執(zhí)行一個(gè)替換操作;
③qr/pattern:返回一個(gè)Regex對(duì)象供今后使用;
④sqlit():把一個(gè)字符串拆分為子字符串;
注意事項(xiàng):
①允許把限定字符放在模式的后面。\i用來(lái)表明搜索時(shí)不區(qū)分字母大小寫(xiě),\g用來(lái)表明進(jìn)行全局搜索;
②使用“回溯引用”時(shí),'將返回被匹配字符串前面的所有東西,`將返回被匹配字符串后面的所有東西;+將返回最后一個(gè)被匹配的子表達(dá)式,&將返回被匹配到的所有東西

A.5 Sun Java

Java對(duì)正則表達(dá)式的支持是從1.4版本開(kāi)始的,此前的JRE(Java Runtime Environment,Java運(yùn)行環(huán)境)不支持正則表達(dá)式。

Java語(yǔ)言中的正則表達(dá)式匹配功能主要通過(guò)java.util.regex.Matcher類和以下方法實(shí)現(xiàn):

find():在一個(gè)字符串里尋找一個(gè)給定模式的匹配;

lookingAt():用一個(gè)給定的模式去嘗試匹配一個(gè)字符串的開(kāi)頭;

matches():用一個(gè)給定的模式去嘗試匹配一個(gè)完整的字符串;

replaceALL():進(jìn)行替換操作,對(duì)所有的匹配都進(jìn)行替換;

replaceFirst():進(jìn)行替換操作,只對(duì)第一個(gè)匹配進(jìn)行替換;

Matcher類還提供了幾個(gè)能讓程序員對(duì)特定操作做出更細(xì)致調(diào)控的方法;此外,java.util.regex.pattern類也提供了幾個(gè)簡(jiǎn)單易用的包裝器方法:

compile():把一個(gè)正則表達(dá)式編譯成一個(gè)模式;

flags():返回某給定模式的匹配標(biāo)志;

matches():在功能上等價(jià)于剛才介紹的matches()方法;

pattern():把一個(gè)模式還原為一個(gè)正則表達(dá)式;

sqlit():把一個(gè)字符串拆分為子字符串;

Sun發(fā)布的Java正則表達(dá)式支持與Perl語(yǔ)言基本兼容,但請(qǐng)注意一下幾項(xiàng)注意事項(xiàng):

①要想使用正則表達(dá)式,必須先用import java.util.regex.*語(yǔ)句導(dǎo)入正則表達(dá)式組件;

②不支持嵌入條件;

③不支持使用\E、\L、\l、\U和\u進(jìn)行字母大小寫(xiě)轉(zhuǎn)換;

④不支持使用[\b]匹配退格符;

⑤不支持\z;

總結(jié)

正則表達(dá)式的基本語(yǔ)法都是差不多的,具體不同,我們可以根據(jù)查表來(lái),仔細(xì)了解,剛剛寫(xiě)正則也遇到很多坑,這個(gè)東西寫(xiě)多了就會(huì)熟悉,不難需要耐心。

最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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