30分鐘學(xué)會(huì)正則表達(dá)式

推薦幾個(gè)正則表達(dá)式編輯器

Debuggex :https://www.debuggex.com/

PyRegex:http://www.pyregex.com/

Regexper:http://www.regexper.com/

正則表達(dá)式是一種查找以及字符串替換操作。正則表達(dá)式在文本編輯器中廣泛使用兼砖,比如正則表達(dá)式被用于:

檢查文本中是否含有指定的特征詞

找出文中匹配特征詞的位置

從文本中提取信息蔚润,比如:字符串的子串

修改文本

與文本編輯器相似磅氨,幾乎所有的高級(jí)編程語(yǔ)言都支持正則表達(dá)式。在這樣的語(yǔ)境下烦租,“文本”也就是一個(gè)字符串叉橱,可以執(zhí)行的操作都是類似的屡贺。一些編程語(yǔ)言(比如Perl甩栈,JavaScript)會(huì)檢查正則表達(dá)式的語(yǔ)法。

正則表達(dá)式是什么突想?

正則表達(dá)式只是一個(gè)字符串袭灯。沒(méi)有長(zhǎng)度限制,但是工腋,這樣的正則表達(dá)式長(zhǎng)度往往較短蟋恬。如下所示是一些正則表達(dá)式的例子:

I had a \S+ day today

[A-Za-z0-9\-_]{3,16}

\d\d\d\d-\d\d-\d\d

v(\d+)(\.\d+)*

TotalMessages="(.*?)"

<[^<>]>

這些字符串實(shí)際上都是微型計(jì)算機(jī)程序。正則表達(dá)式的語(yǔ)法矾飞,實(shí)際上是一種輕量級(jí)豹绪、簡(jiǎn)潔、適用于特定領(lǐng)域的編程語(yǔ)言括尸。記住這一點(diǎn),那么你就很容易理解下面的事情:

每一個(gè)正則表達(dá)式啦膜,都可以分解為一個(gè)指令序列雀摘,比如“先找到這樣的字符,再找到那樣的字符清蚀,再?gòu)闹姓业揭粋€(gè)字符枷邪。。救斑×澈颍”

每一個(gè)正則表達(dá)式都有輸入(文本)和輸出(匹配規(guī)則的輸出,有時(shí)是修改后的文本)

正則表達(dá)式有可能出現(xiàn)語(yǔ)法錯(cuò)誤——不是所有的字符串都是正則表達(dá)式

正則表達(dá)式語(yǔ)法很有個(gè)性携添,也可以說(shuō)很恐怖

有時(shí)可以通過(guò)編譯烈掠,使得正則表達(dá)式執(zhí)行更快

在實(shí)現(xiàn)中瘾蛋,正則表達(dá)式還有其他的特點(diǎn)。本文將重點(diǎn)討論正則表達(dá)式的核心語(yǔ)法取董,在幾乎所有的正則表達(dá)式中都可以見(jiàn)到這些規(guī)則。

特別提示:正則表達(dá)式與文件通配語(yǔ)法無(wú)關(guān)经窖,比如 *.xml

正則表達(dá)式的基礎(chǔ)語(yǔ)法

字符

正則表達(dá)式中包含了一系列的字符,這些字符只能匹配它們本身配乱。有一些被稱為“元字符”的特殊字符,可以匹配一些特殊規(guī)則。

如下所示的例子中爆阶,我用紅色標(biāo)出了元字符班套。

I had a\S+day today

[A-Za-z0-9\-_]{3,16}

\d\d\d\d-\d\d-\d\d

v(\d+)(\.\d+)*

TotalMessages="(.*?)"

<[^<>]*>

大部分的字符,包括所有的字母和數(shù)字字符理盆,是普通字符熏挎。也就意味著养匈,它們只能匹配它們自己积担,如下所示的正則表達(dá)式:

cat

意味著,只能匹配一個(gè)字符串的烁,以“c”開(kāi)頭,然后是字符“a”雅镊,緊跟著是字符“t”的字符串襟雷。

到目前為止,正則表達(dá)式的功能類似于

常規(guī)的Find功能

Java中的String.indexOf()函數(shù)

PHP中的strpos()函數(shù)

等等

注意:不做特殊說(shuō)明仁烹,正則表達(dá)式中是區(qū)分大小寫的耸弄。但是,幾乎所有正則表達(dá)式的實(shí)現(xiàn)晃危,都會(huì)提供一個(gè)Flag用來(lái)控制是否區(qū)分大小寫叙赚。

點(diǎn)“.”

我們第一個(gè)要講解的元字符是“.”。這個(gè)符號(hào)意味著可以匹配任意一個(gè)字符苇瓣。如下所示的正則表達(dá)式:

c.t

意味著匹配“以c開(kāi)頭,之后是任意一個(gè)字符眠副,緊跟著是字母t”的字符串台丛。

在一段文本中疫衩,這樣的正則表達(dá)式可以用來(lái)找出cat,cot,czt這樣的字符串,甚至可以找出c.t這樣的組合缀遍,但是不能找到ct或者是coot這樣的字符串减宣。

使用反斜杠“\”可以忽略元字符,使得元字符的功能與普通字符一樣。所以衡蚂,正則表達(dá)式

c\.t

表示“找到字母c,然后是一個(gè)句號(hào)(“.”)七咧,緊跟著字母t”

反斜杠本身也是一個(gè)元字符拇泣,這意味著反斜杠本身也可以通過(guò)相似的方法變回到普通字符的用途序芦。因此,正則表達(dá)式

c\\t

表示匹配“以字符c開(kāi)頭,然后是一個(gè)反斜杠,緊跟著是字母t”的字符串。

注意怠苔!在正則表達(dá)式的實(shí)現(xiàn)中,.是不能用于匹配換行符的很洋∫掌眨”換行符“的表示方法在不同實(shí)現(xiàn)中也不同簸州。實(shí)際編程時(shí),請(qǐng)參考相關(guān)文檔歧譬。在本文中岸浑,我認(rèn)為.是可以匹配任意字符的。實(shí)現(xiàn)環(huán)境通常會(huì)提供一個(gè)Flag標(biāo)志位瑰步,來(lái)控制這一點(diǎn)矢洲。

字符類

字符類是一組在方括號(hào)內(nèi)的字符,表示可以匹配其中的任何一個(gè)字符缩焦。

正則表達(dá)式c[aeiou]t读虏,表示可以匹配的字符串是”以c開(kāi)頭,接著是aeiou中的任何一個(gè)字符袁滥,最后以t結(jié)尾”盖桥。在文本的實(shí)際應(yīng)用中,這樣的正則表達(dá)式可以匹配:cat,cet,cit,cot,cut五種字符串题翻。

正則表達(dá)式[0123456789]表示匹配任意一個(gè)整數(shù)揩徊。

正則表達(dá)式[a]表示匹配單字符a。

包含忽略字符的例子

a

表示匹配字符串[a]

[\[\]\ab]表示匹配的字符為”[“或者”]”或者”a”,或者”b”

[\\\[\]]表示匹配的字符為”\”或者 “[”或者”]”

在字符類中,字符的重復(fù)和出現(xiàn)順序并不重要塑荒。[dabaaabcc]與[abc]是相同的

重要提示:字符類中和字符類外的規(guī)則有時(shí)不同熄赡,一些字符在字符類中是元字符,在字符類外是普通字符袜炕。一些字符正好相反本谜。還有一些字符在字符類中和字符類外都是元字符,這要視情況而定偎窘!

比如乌助,.表示匹配任意一個(gè)字符,而[.]表示匹配一個(gè)全角句號(hào)陌知。這不是一回事他托!

字符類的范圍

在字符集中,你可以通過(guò)使用短橫線來(lái)表示匹配字母或數(shù)字的范圍仆葡。

[b-f]與[b,c,d,e,f]相同赏参,都是匹配一個(gè)字符”b”或”c”或”d”或”e”或”f”

[A-Z]與[ABCDEFGHIJKLMNOPQRSTUVWXYZ]相同,都是匹配任意一個(gè)大寫字母沿盅。

[1-9]與[123456789]相同把篓,都是匹配任意一個(gè)非零數(shù)字。

練習(xí)

使用目前我們已經(jīng)講解的正則表達(dá)式相關(guān)知識(shí)腰涧,在字典中匹配找到含有最多連續(xù)元音的單詞韧掩,同時(shí)找到含有最多連續(xù)輔音的單詞。

答案

[aeiou][aeiou][aeiou][aeiou][aeiou][aeiou]這樣的正則表達(dá)式窖铡,可以匹配連續(xù)含有六個(gè)元音的單詞疗锐,比如euouae和euouaes。

同樣的费彼,恐怖的正則表達(dá)式[bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz]可以找到連續(xù)含有十個(gè)輔音的單詞sulphhydryls.

下文中滑臊,我們會(huì)講解,怎樣有效縮短這樣的正則表達(dá)式長(zhǎng)度箍铲。

在字符類之外雇卷,短橫線沒(méi)有特殊含義。正則表達(dá)式a-z颠猴,表示匹配字符串“以a開(kāi)頭聋庵,然后是一個(gè)短橫線,以z結(jié)尾”芙粱。

范圍和單獨(dú)的字符可能在一個(gè)字符類中同時(shí)出現(xiàn):

[0-9.,]表明匹配一個(gè)數(shù)字祭玉,或者一個(gè)全角句號(hào),或者一個(gè)逗號(hào)

[0-9a-fA-F]意味著匹配一個(gè)十六進(jìn)制數(shù)

[a-zA-Z0-9\-]意味著匹配一個(gè)字母春畔、數(shù)字或者一個(gè)短橫線

練習(xí)

使用已經(jīng)介紹過(guò)的正則表達(dá)式知識(shí)脱货,匹配YYYY-MM-DD格式的日期岛都。

答案

[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].

同樣的,下文中振峻,我們會(huì)介紹怎樣有效減少這樣的正則表達(dá)式長(zhǎng)度臼疫。

雖然你可以嘗試在正則表達(dá)式中使用一些非字母或數(shù)字作為范圍的最后一個(gè)符號(hào),比如abc[!-/]def扣孟,但是這并不是在每種實(shí)現(xiàn)中都合法烫堤。即使這樣的語(yǔ)法是合法的,這樣的語(yǔ)義也是模糊的凤价。最好不要這樣使用鸽斟。

同時(shí),你必須謹(jǐn)慎選擇范圍的邊界值利诺。即使[A-z]在你使用的實(shí)現(xiàn)中富蓄,是合法的,也可能會(huì)產(chǎn)生無(wú)法預(yù)料的運(yùn)行結(jié)果慢逾。(注意立倍,在z到a之間,是有字符存在的)

注意:范圍的字符值代表的是字符而已侣滩,并不能代表數(shù)值范圍口注,比如[1-31]表示匹配一個(gè)數(shù)字,是1或者2或者3君珠,而不是匹配一個(gè)數(shù)值在1到31之間的數(shù)寝志。

字符類的反義

你可以在字符類的起始位放一個(gè)反義符。

[^a]表示匹配任何不是“a”的字符

[^a-zA-Z0-9]表示匹配任何不是字母也不是數(shù)字的字符

[\^abc]匹配一個(gè)為“^”或者a或者b或者c的字符

[^\^]表示匹配任何不為“^”的字符

練習(xí)

在字典中葛躏,找到一個(gè)不滿足“在e之前有i,但是沒(méi)有c”的例子悠菜。

答案

cie和[^c]ei都要可以找到很多這樣的例子舰攒,比如ancient,science,viel,weigh

轉(zhuǎn)義字符類

\d這個(gè)正則表達(dá)式與[0-9]作用相同,都是匹配任何一個(gè)數(shù)字悔醋。(要匹配\d,應(yīng)該使用正則表達(dá)式\\d)

\w與[0-9A-Za-z]相同摩窃,都表示匹配一個(gè)數(shù)字或字母字符

\s意味著匹配一個(gè)空字符(空格,制表符芬骄,回車或者換行)

另外

\D與[^0-9]相同猾愿,表示匹配一個(gè)非數(shù)字字符。

\W與[^0-9A-Za-z]相同账阻,表示匹配一個(gè)非數(shù)字同時(shí)不是字母的字符蒂秘。

\S表示匹配一個(gè)非空字符。

這些是你必須掌握的字符淘太。你可能已經(jīng)注意到了姻僧,一個(gè)全角句號(hào)“.”也是一個(gè)字符類规丽,可以匹配任意一個(gè)字符。

很多正則表達(dá)式的實(shí)現(xiàn)中撇贺,提供了更多的字符類赌莺,或者是標(biāo)志位在ASCII碼的基礎(chǔ)上,擴(kuò)展現(xiàn)有的字符類松嘶。

特別提示:統(tǒng)一字符集中包含除了0至9之外的更多數(shù)字字符艘狭,同樣的,也包含更多的空字符和字母字符翠订。實(shí)際使用正則表達(dá)式時(shí)巢音,請(qǐng)仔細(xì)查看相關(guān)文檔。

練習(xí)

簡(jiǎn)化正則表達(dá)式[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].

答案

\d\d\d\d-\d\d-\d\d.

重復(fù)

在字符或字符集之后蕴轨,你可以使用{ }大括號(hào)來(lái)表示重復(fù)

正則表達(dá)式a{1}與a意思相同港谊,都表示匹配字母a

a{3}表示匹配字符串“aaa”

a{0}表示匹配空字符串。從這個(gè)正則表達(dá)式本身來(lái)看橙弱,它毫無(wú)意義歧寺。如果你對(duì)任何文本執(zhí)行這樣的正則表達(dá)式,你可以定位到搜索的起始位置棘脐,即使文本為空斜筐。

a\{2\}表示匹配字符串“a{2}”

在字符類中,大括號(hào)沒(méi)有特殊含義蛀缝。[{}]表示匹配一個(gè)左邊的大括號(hào)顷链,或者一個(gè)右邊的大括號(hào)

練習(xí)

簡(jiǎn)化下面的正則表達(dá)式

z.......z

\d\d\d\d-\d\d-\d\d

[aeiou][aeiou][aeiou][aeiou][aeiou][aeiou]

[bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz][bcdfghjklmnpqrstvwxyz]

答案

z.{7}z

\d{4}-\d{2}-\d{2}

[aeiou]{6}

[bcdfghjklmnpqrstvwxyz]{10}

注意:重復(fù)字符是沒(méi)有記憶性的,比如[abc]{2}表示先匹配”a或者b或者c”屈梁,再匹配”a或者b或者c”嗤练,與匹配”aa或者ab或者ac或者ba或者bb或者bc或者ca或者cb或者cc“一樣。[abc]{2}并不能表示匹配”aa或者bb或者cc“

指定重復(fù)次數(shù)范圍

重復(fù)次數(shù)是可以指定范圍的

x{4,4}與x{4}相同

colou{0,1}r表示匹配colour或者color

a{3,5}表示匹配aaaaa或者aaaa或者aaa

注意這樣的正則表達(dá)式會(huì)優(yōu)先匹配最長(zhǎng)字符串在讶,比如輸入I had an aaaaawful day會(huì)匹配單詞aaaaawful中的aaaaa煞抬,而不會(huì)匹配其中的aaa。

重復(fù)次數(shù)是可以有范圍的构哺,但是有時(shí)候這樣的方法也不能找到最佳答案革答。如果你的輸入文本是I had an aaawful daaaaay那么在第一次匹配時(shí),只能找到aaawful曙强,只有再次執(zhí)行匹配時(shí)才能找到daaaaay中的aaaaa.

重復(fù)次數(shù)的范圍可以是開(kāi)區(qū)間

a{1残拐,}表示匹配一個(gè)或一個(gè)以上的連續(xù)字符a。依然是匹配最長(zhǎng)字符串碟嘴。當(dāng)找到第一個(gè)a之后溪食,正則表達(dá)式會(huì)嘗試匹配盡量多個(gè)的連續(xù)字母a。

.{0,}表示匹配任意內(nèi)容娜扇。無(wú)論你輸入的文本是什么眠菇,即使是一個(gè)空字符串边败,這個(gè)正則表達(dá)式都會(huì)成功匹配全文并返回結(jié)果。

練習(xí)

使用正則表達(dá)式找到雙引號(hào)捎废。要求輸入字符串可能包含任意個(gè)字符笑窜。

調(diào)整你的正則表達(dá)式使得在一對(duì)雙引號(hào)中間不再包含其他的雙引號(hào)。

答案

".{0,}", 然后"[^"]{0,}".

關(guān)于重復(fù)的轉(zhuǎn)義字符

登疗?與{0,1}相同排截,比如,colou?r表示匹配colour或者color

*與{0,}相同辐益。比如断傲,.*表示匹配任意內(nèi)容

+與{1,}相同智政。比如,\w+表示匹配一個(gè)詞认罩。其中”一個(gè)詞”表示由一個(gè)或一個(gè)以上的字符組成的字符串,比如_var或者AccountName1.

這些是你必須知道的常用轉(zhuǎn)義字符续捂,除此之外還有:

\?\*\+ 表示匹配字符串”?*+”

[?*+]表示匹配一個(gè)問(wèn)號(hào)垦垂,或者一個(gè)*號(hào),或者一個(gè)加號(hào)

練習(xí)

簡(jiǎn)化下列的正則表達(dá)式:

".{0,}"and"[^"]{0,}"

x?x?x?

y*y*

z+z+z+z+

答案

".*"and"[^"]*"

x{0,3}

y*

z{4,}

練習(xí)

寫出正則表達(dá)式牙瓢,尋找由非字母字符分隔的兩個(gè)單詞劫拗。如果是三個(gè)呢?六個(gè)呢矾克?

\w+\W+\w+,\w+\W+\w+\W+\w+,\w+\W+\w+\W+\w+\W+\w+\W+\w+\W+\w+.

下文中页慷,我們將簡(jiǎn)化這個(gè)正則表達(dá)式。

非貪婪匹配

正則表達(dá)式 “.*” 表示匹配雙引號(hào)胁附,之后是任意內(nèi)容酒繁,之后再匹配一個(gè)雙引號(hào)。注意控妻,其中匹配任意內(nèi)容也可以是雙引號(hào)州袒。通常情況下,這并不是很有用饼暑。通過(guò)在句尾加上一個(gè)問(wèn)號(hào)稳析,可以使得字符串重復(fù)不再匹配最長(zhǎng)字符洗做。

\d{4,5}?表示匹配\d\d\d\d或者\(yùn)d\d\d\d\d弓叛。也就是和\d{4}一樣

colou??r與colou{0,1}r相同,表示找到color或者colour诚纸。這與colou?r一樣撰筷。

“.*?”表示先匹配一個(gè)雙引號(hào),然后匹配最少的字符畦徘,然后是一個(gè)雙引號(hào)毕籽,與上面兩個(gè)例子不同抬闯,這很有用。

選擇匹配

你可以使用|來(lái)分隔可以匹配的不同選擇:

cat|dog表示匹配”cat”或者”dog”

red|blue|以及red||blue以及|red|blue都表示匹配red或者blue或者一個(gè)空字符串

a|b|c與[abc]相同

cat|dog|\|表示匹配”cat”或者”dog”或者一個(gè)分隔符”|“

[cat|dog]表示匹配a或者c或者d或者g或者o或者t或者一個(gè)分隔符“|”

練習(xí)

簡(jiǎn)化下列正則表達(dá)式:

s|t|u|v|w

aa|ab|ba|bb

[abc]|[^abc]

[^ab]|[^bc]

[ab][ab][ab]?[ab]?

答案

[s-w]

[ab]{2}

.

[^b]

[ab]{2,4}

練習(xí)

使用正則表達(dá)式匹配1到31之間的整數(shù)关筒,[1-31]不是正確答案溶握!

這樣的正則表達(dá)式不唯一.[1-9]|[12][0-9]|3[01]是其中之一。

分組

你可以使用括號(hào)表示分組:

通過(guò)使用Mon|Tues|Wednes|Thurs|Fri|Satur|Sun)day匹配一周中的某一天

(\w*)ility與\w*ility相同蒸播。都是匹配一個(gè)由”ility”結(jié)尾的單詞睡榆。稍后我們會(huì)講解,為何第一種方法更加有用袍榆。

表示匹配一對(duì)括號(hào)胀屿。

[()]表示匹配任意一個(gè)左括號(hào)或者一個(gè)右括號(hào)

練習(xí)

在《時(shí)間機(jī)器中》找到一對(duì)括號(hào)中的內(nèi)容,然后通過(guò)修改正則表達(dá)式包雀,找到不含括號(hào)的內(nèi)容宿崭。

答案

.?. 然后是,[()]?.

分組可以包括空字符串:

(red|blue)表示匹配red或者blue或者是一個(gè)空字符串

abc()def與abcdef相同

你也可以在分組的基礎(chǔ)上使用重復(fù):

(red|blue)?與(red|blue|)相同

\w+(\s+\w+)表示匹配一個(gè)或多個(gè)由空格分隔的單詞

練習(xí)

簡(jiǎn)化正則表達(dá)式\w+\W+\w+\W+\w+以及\w+\W+\w+\W+\w+\W+\w+\W+\w+\W+\w+.

答案

\w+(\W+\w+){2},\w+(\W+\w+){5}.

單詞分隔符

在單詞和非單詞之間有單詞分隔符才写。記住葡兑,一個(gè)單詞\w是[0-9A-Za-z_]抱环,而非單詞字符是\W(大寫)缎谷,表示[^0-9A-Za-z_].

在文本的開(kāi)頭和結(jié)尾通常也有單詞分隔符盘榨。

在輸入文本it’s a cat中为狸,實(shí)際有八個(gè)單詞分隔符针饥。如果我們?cè)赾at之后在上一個(gè)空格淘这,那就有九個(gè)單詞分隔符袁梗。.

\b表示匹配一個(gè)單詞分隔符

\b\w\w\w\b表示匹配一個(gè)三字母單詞

a\ba表示匹配兩個(gè)a中間有一個(gè)單詞分隔符鲁猩。這個(gè)正則表達(dá)式永遠(yuǎn)不會(huì)有匹配的字符轰异,無(wú)論輸入怎樣的文本岖沛。

單詞分隔符本身并不是字符。它們的寬度為0搭独。下列正則表達(dá)式的作用不同

(\bcat)\b

(\bcat\b)

\b(cat)\b

\b(cat\b)

練習(xí)

在詞典中找到最長(zhǎng)的單詞婴削。

答案

在嘗試之后發(fā)現(xiàn),\b.{45,}\b可以在字典中找到最長(zhǎng)單詞

換行符

一篇文本中可以有一行或多行牙肝,行與行之間由換行符分隔唉俗,比如:

Line一行文字

Line break換行符

Line一行文字

Line break換行符

Line break換行符

Line一行文字

注意,所有的文本都是以一行結(jié)束的配椭,而不是以換行符結(jié)束虫溜。但是,任意一行都可能為空股缸,包括最后一行衡楞。

行的起始位置,是在換行符和下一行首字符之間的空間敦姻●常考慮到單詞分隔符歧杏,文本的起始位置也可以當(dāng)做是首行位置。

最后一行是最后一行的尾字符和換行符之間的空間迷守∪蓿考慮到單詞分隔符,文本的結(jié)束也可以認(rèn)為是行的結(jié)束兑凿。

那么新的格式表示如下:

Start-of-line, line, end-of-line

Line break

Start-of-line, line, end-of-line

Line break

Line break

Start-of-line, line, end-of-line

基于上述概念:

^表示匹配行的開(kāi)始位置

$表示匹配行的結(jié)束位置

^&表示一個(gè)空行

^.*&表示匹配全文內(nèi)容懂更,因?yàn)樾械拈_(kāi)始符號(hào)也是一個(gè)字符,"."會(huì)匹配這個(gè)符號(hào)急膀。找到單獨(dú)的一行沮协,可以使用^.*?$

\^\$表示匹配字符串“^$”

[$]表示匹配一個(gè)$。但是卓嫂,[^]不是合法的正則表達(dá)式慷暂。記住在方括號(hào)中,字符有不同的特殊含義晨雳。要想在方括號(hào)內(nèi)匹配^行瑞,必須用[\^]

與字符分隔符一樣,換行符也不是字符餐禁。它們寬度為0.如下所示的正則表達(dá)式作用不同:

(^cat)$

(^cat$)

^(cat)$

^(cat$)

練習(xí)

使用正則表達(dá)式在《時(shí)間機(jī)器》中找到最長(zhǎng)的一行血久。

答案

使用正則表達(dá)式^.{73,}$可以匹配長(zhǎng)度為73的一行

文本分界

在很多的正則表達(dá)式實(shí)現(xiàn)中,將^和$作為文本的開(kāi)始符號(hào)和結(jié)束符號(hào)帮非。

還有一些實(shí)現(xiàn)中氧吐,用\A和\z作為文本的開(kāi)始和結(jié)束符號(hào)。

捕捉和替換

從這里開(kāi)始末盔,正則表達(dá)式真正體現(xiàn)出了它的強(qiáng)大筑舅。

捕獲組

你已經(jīng)知道了使用括號(hào)可以匹配一組符號(hào)。使用括號(hào)也可以捕獲子串陨舱。假設(shè)正則表達(dá)式是一個(gè)小型計(jì)算機(jī)程序翠拣,那么捕獲子串就是它輸出的一部分。

正則表達(dá)式(\w*)ility表示匹配以ility結(jié)尾的詞游盲。第一個(gè)被捕獲的部分是由\w*控制的误墓。比如,輸入的文本內(nèi)容中有單詞accessibility益缎,那么首先被捕獲的部分是accessib谜慌。如果輸入的文本中有單獨(dú)的ility,則首先被捕獲的是一個(gè)空字符串链峭。

你可能會(huì)有很多的捕獲字符串畦娄,它們可能靠得很近又沾。捕獲組從左向右編號(hào)弊仪。也就是只需要對(duì)左括號(hào)計(jì)數(shù)熙卡。

假設(shè)有這樣的正則表達(dá)式:(\w+) had a ((\w+) \w+)

輸入的內(nèi)容是:I had a nice day

捕獲組1:I

捕獲組2:nice day

捕獲組3:nice

在一些正則表達(dá)式的實(shí)現(xiàn)中,你可以從零開(kāi)始編號(hào)励饵,編號(hào)零表示匹配整句話:I had a nice day.

在其他的實(shí)現(xiàn)中驳癌,如果沒(méi)有制定捕獲組,那么捕獲組1會(huì)自動(dòng)地填入捕獲組0的信息役听。

是的颓鲜,這也意味著會(huì)有很多的括號(hào)。有一些正則表達(dá)式的實(shí)現(xiàn)中典予,提供了“非捕獲組”的語(yǔ)法甜滨,但是這樣的語(yǔ)法并不是標(biāo)準(zhǔn)語(yǔ)法,因此我們不會(huì)介紹瘤袖。

從一個(gè)成功的匹配中返回的捕獲組個(gè)數(shù)衣摩,與使用原來(lái)的正則表達(dá)式獲得的捕獲組個(gè)數(shù)相同。記住這一點(diǎn)捂敌,你可以解釋一些奇怪的現(xiàn)象艾扮。.

正則表達(dá)式((cat)|dog)表示匹配cat或者dog。這里有兩個(gè)捕獲組占婉,如果輸入文本是dog泡嘴,那么捕獲組1是dog,捕獲組2為空。

正則表達(dá)式a(\w)*表示匹配一個(gè)以a開(kāi)頭的單詞逆济。這里只有一個(gè)捕獲組

如果輸入文本為a,捕獲組1為空酌予。

如果輸入文本為ad,捕獲組為d

如果輸入文本為avocado,捕獲組1為v奖慌。但是捕獲組0表示整個(gè)單詞avocado.

替換

假如你使用了一個(gè)正則表達(dá)式去匹配字符串霎终,你可以描述另外一個(gè)字符串來(lái)替換其中的匹配字符。用來(lái)替換的字符串稱為替換表達(dá)式升薯。它的功能類似于

常規(guī)的Replace會(huì)話

Java中的String.replace()函數(shù)

PHP的str_replace()函數(shù)

等等

練習(xí)

將《時(shí)間機(jī)器》中所有的元音字母替換為r莱褒。

答案

使用正則表達(dá)式[aeiou]以及[AEIOU],對(duì)應(yīng)的替換字符串分別為r,R.

但是涎劈,你可以在替換表達(dá)式中引用捕獲組广凸。這是在替換表達(dá)式中,你可以唯一操作的地方蛛枚。這也是非常有效的谅海,因?yàn)檫@樣你就不用重構(gòu)你找到的字符串。

假設(shè)你正在嘗試將美國(guó)風(fēng)格的日期表示MM/DD/YY替換為ISO 8601日期表示YYYY-MM-DD

從正則表達(dá)式(\d\d)/(\d\d)/(\d\d)開(kāi)始蹦浦。注意扭吁,這其中有三個(gè)捕獲組:月份,日期和兩位的年份。

.捕獲組的內(nèi)容和捕獲組編號(hào)之間用反斜杠分隔侥袜,因此你的替換表達(dá)式應(yīng)該是20\3-\1-\2.

如果我們輸入的文本中包含03/04/05表示2005年3月4日那么:

捕獲組1:03

捕獲組2:04

捕獲組3:05

替換字符串2005-03-04.

在替換表達(dá)式中蝌诡,你可以多次使用捕獲組

對(duì)于雙元音,正則表達(dá)式為([aeiou])枫吧,替換表達(dá)式為\l\l

在替換表達(dá)式中不能使用反斜杠浦旱。比如,你在計(jì)算機(jī)程序中希望使用字符串中使用部分文本九杂。那么颁湖,你必須在每個(gè)雙引號(hào)或者反斜杠之前加上反斜杠。

你的正則表達(dá)式可以是([\\”])例隆。捕獲組1是雙引號(hào)或者反斜杠

你的替換表達(dá)式應(yīng)該是\\\l

在某些實(shí)現(xiàn)中甥捺,采用美元符號(hào)$代替\

練習(xí)

使用正則表達(dá)式和替換表達(dá)式,將23h59這樣的時(shí)間戳轉(zhuǎn)化為23:59.

答案

正則表達(dá)式finds the timestamps, 替換表達(dá)式\1:\2

反向引用

在一個(gè)正則表達(dá)式中镀层,你也可以引用捕獲組涎永。這稱作:反向引用

比如,[abc]{2}表示匹配aa或者ab或者ac或者ba或者bb或者bc或者ca或者cb或者cc.但是{[abc]}\1表示只匹配aa或者bb或者cc.

練習(xí)

在字典中鹿响,找到包含兩次重復(fù)子串的最長(zhǎng)單詞羡微,比如papa,coco

\b(.{6,})\1\b匹配chiquichiqui.

如果我們不在乎單詞的完整性,我們可以忽略單詞的分解惶我,使用正則表達(dá)式(.{7,})\1匹配countercountermeasure以及countercountermeasures.

使用正則表達(dá)式編程

特別提醒:

過(guò)度使用的反斜杠

在一些編程語(yǔ)言妈倔,比如Java中,對(duì)于包含正則表達(dá)式的字符串沒(méi)有特殊標(biāo)記绸贡。字符串有著自己的過(guò)濾規(guī)則盯蝴,這是優(yōu)先于正則表達(dá)式規(guī)則的,這是頻繁使用反斜杠的原因听怕。

比如在Java中

匹配一個(gè)數(shù)字捧挺,使用的正則表達(dá)式從\d變?yōu)榇a中的String re= “\\d”

匹配雙引號(hào)字符串的正則表達(dá)式從"[^"]*"變?yōu)镾tring re = “\”[^\”]*\””

匹配反斜杠或者是左邊方括號(hào),或者右邊方括號(hào)的正則表達(dá)式從[\\\[\]]變?yōu)镾tring re = “[\\\\\

]”;

String re = "\\s";和String re = "[ \t\r\n]";是等價(jià)的. 注意它們實(shí)際執(zhí)行調(diào)用時(shí)的層次不同尿瞭。

在其他的編程語(yǔ)言中闽烙,正則表達(dá)式是由特殊標(biāo)明的,比如使用/声搁。下面是JavaScript的例子:

匹配一個(gè)數(shù)字黑竞,\d會(huì)簡(jiǎn)單寫成var regExp = /\d/;.

匹配一個(gè)反斜杠或者一個(gè)左邊的方括號(hào)或者一個(gè)右邊的方括號(hào),var regExp = /[\\\[\]]/;

var regExp = /\s/;和var regExp = /[ \t\r\n]/;是等價(jià)的

當(dāng)然疏旨,這意味著在使用/時(shí)必須重復(fù)兩次很魂。比如找到URL必須使用var regExp = /https?:\/\//;.

我希望現(xiàn)在你能明白,我為什么讓你特別注意反斜杠檐涝。

動(dòng)態(tài)正則表達(dá)式

當(dāng)你動(dòng)態(tài)創(chuàng)建一個(gè)正則表達(dá)式的時(shí)候請(qǐng)?zhí)貏e小心遏匆。如果你使用的字符串不夠完善的花法挨,可能會(huì)有意想不到的匹配結(jié)果。這可能導(dǎo)致語(yǔ)法錯(cuò)誤幅聘,更糟糕的是凡纳,你的正則表達(dá)式語(yǔ)法正確,但是結(jié)果無(wú)法預(yù)料喊暖。

錯(cuò)誤的Java代碼:

String sep = System.getProperty(“file.separator”); String[] directories = filePath.split(sep);

Bug:String.split()認(rèn)為sep是一個(gè)正則表達(dá)式。但是撕瞧,在Windows中陵叽,Sep是表示匹配一個(gè)反斜杠,也就是與正則表達(dá)式”\\”相同丛版。這個(gè)正則表達(dá)式是正確的巩掺,但是會(huì)返回一個(gè)異常:PatternSyntaxException.

任何好的編程語(yǔ)言都會(huì)提供一種良好的機(jī)制來(lái)跳過(guò)字符串中所有的元字符。在Java中页畦,你可以這樣實(shí)現(xiàn):

String sep = System.getProperty(“file.separator”);

String[] directories = filePath.split(Pattern.quote(sep));

循環(huán)中的正則表達(dá)式

將正則表達(dá)式字符串加入反復(fù)運(yùn)行的程序中胖替,是一種開(kāi)銷很大的操作。如果你可以在循環(huán)中避免使用正則表達(dá)式豫缨,你可以大大提高效率独令。

其他建議

輸入驗(yàn)證

正則表達(dá)式可以用來(lái)進(jìn)行輸入驗(yàn)證。但是嚴(yán)格的輸入驗(yàn)證會(huì)使得用戶體驗(yàn)較差好芭。比如:

信用卡號(hào)

在一個(gè)網(wǎng)站上燃箭,我輸入了我的卡號(hào)比如1234 5678 8765 4321網(wǎng)站拒絕接收。因?yàn)樗褂昧苏齽t表達(dá)式\d{16}舍败。

正則表達(dá)式應(yīng)該考慮到用戶輸入的空格和短橫線招狸。

實(shí)際上,為什么不先過(guò)濾掉所有的非數(shù)字字符邻薯,然后再進(jìn)行有效性驗(yàn)證呢裙戏?這樣做,可以先使用\D以及空的替換表達(dá)式厕诡。

練習(xí)

在不先過(guò)濾掉所有的非數(shù)字字符的情況下累榜,使用正則表達(dá)式驗(yàn)證卡號(hào)的正確性。

答案

\D*(\d\D*){16}is one of several variations which would accomplish this.

名字

不要使用正則表達(dá)式來(lái)驗(yàn)證姓名灵嫌。實(shí)際上信柿,即使可以,也不要企圖驗(yàn)證姓名醒第。

程序員對(duì)名字的錯(cuò)誤看法:

名字中不含空格

名字中沒(méi)有連接符號(hào)

名字中只會(huì)使用ASCII碼字符

名字中出現(xiàn)的字都在特殊字符集中

名字至少要有M個(gè)字的長(zhǎng)度

名字不會(huì)超過(guò)N個(gè)字的長(zhǎng)度

人們只有一個(gè)名

人們只有一個(gè)中間名

人們只有一個(gè)姓(最后三條是從英語(yǔ)的人名考慮)

電子郵件地址

不要使用正則表達(dá)式驗(yàn)證郵箱地址的正確性渔嚷。

首先,這樣的驗(yàn)證很難是精確的稠曼。電子郵件地址是可以用正則表達(dá)式驗(yàn)證的形病,但是表達(dá)式會(huì)非常的長(zhǎng)并且復(fù)雜。

短的正則表達(dá)式會(huì)導(dǎo)致錯(cuò)誤。(你知道嗎漠吻?電子郵箱地址中會(huì)有一些注釋)

第二量瓜,即使一個(gè)電子郵件地址可以成功匹配正則表達(dá)式,也不代表這個(gè)郵箱實(shí)際存在途乃。郵箱的唯一驗(yàn)證方法绍傲,是發(fā)送驗(yàn)證郵件。

注意

在嚴(yán)格的應(yīng)用場(chǎng)景中耍共,不要使用正則表達(dá)式來(lái)解析HTML或者XML烫饼。解析HTML或者XML:

使用簡(jiǎn)單的正則表達(dá)式不能完成

總體來(lái)說(shuō)非常困難

已經(jīng)有其他的方法解決

找到一個(gè)已經(jīng)有的解析庫(kù)來(lái)完成這個(gè)工作

這就是55分鐘的全部?jī)?nèi)容

總結(jié):

字符:abcd1234etc.

字符類:.[abc][a-z]\d\w\s

.代表任何字符

\d表示“數(shù)字”

\w表示”字母”,[0-9A-Za-z_]

\s表示 “空格, 制表符,回車或換行符”

否定字符類:[^abc]\D\W\S

重復(fù):{4}{3,16}{1,}?*+

?表示 “零次或一次”

*表示 “大于零次”

+表示 “一次或一次以上”

如果不加上?试读,所有的重復(fù)都是最長(zhǎng)匹配的(貪婪)

分組:(Septem|Octo|Novem|Decem)ber

詞杠纵,行以及文本的分隔:\b^$\A\z

轉(zhuǎn)義字符:\1\2\3etc. (在匹配表達(dá)式和替換表達(dá)式中都可用)

元字符:.\[]{}?*+|()^$

在字符類中使用元字符:[]\-^

使用反斜杠可以忽略元字符:\

致謝

正則表達(dá)式非常常用而且非常有用。每個(gè)人在編輯文本或是編寫程序時(shí)都必須了解怎樣使用正則表達(dá)式钩骇。

練習(xí)

選擇正則表達(dá)式的某種實(shí)現(xiàn)比藻,閱讀相關(guān)文檔。我保證倘屹,你會(huì)學(xué)到更多银亲。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市纽匙,隨后出現(xiàn)的幾起案子群凶,更是在濱河造成了極大的恐慌,老刑警劉巖哄辣,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件请梢,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡力穗,警方通過(guò)查閱死者的電腦和手機(jī)毅弧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)当窗,“玉大人够坐,你說(shuō)我怎么就攤上這事⊙旅妫” “怎么了元咙?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)巫员。 經(jīng)常有香客問(wèn)我庶香,道長(zhǎng),這世上最難降的妖魔是什么简识? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任赶掖,我火速辦了婚禮感猛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘奢赂。我一直安慰自己陪白,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布膳灶。 她就那樣靜靜地躺著咱士,像睡著了一般。 火紅的嫁衣襯著肌膚如雪轧钓。 梳的紋絲不亂的頭發(fā)上序厉,一...
    開(kāi)封第一講書(shū)人閱讀 48,970評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音聋迎,去河邊找鬼脂矫。 笑死枣耀,一個(gè)胖子當(dāng)著我的面吹牛霉晕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播捞奕,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼牺堰,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了颅围?” 一聲冷哼從身側(cè)響起伟葫,我...
    開(kāi)封第一講書(shū)人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎院促,沒(méi)想到半個(gè)月后筏养,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡常拓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年渐溶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弄抬。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡茎辐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出掂恕,到底是詐尸還是另有隱情拖陆,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布懊亡,位于F島的核電站依啰,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏店枣。R本人自食惡果不足惜孔飒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一灌闺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧坏瞄,春花似錦桂对、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至缀棍,卻和暖如春宅此,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背爬范。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工父腕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人青瀑。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓璧亮,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親斥难。 傳聞我的和親對(duì)象是個(gè)殘疾皇子枝嘶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

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