正則表達(dá)式簡介
Perl最重要的一大特色就是對(duì)正則表達(dá)式的強(qiáng)力支持,這些支持提供了強(qiáng)大且靈活的字符串處理能力。正則表達(dá)式實(shí)質(zhì)上是Perl內(nèi)嵌的,自成一體的微型編程語言。其不只是Perl的一部分,在很多其他語言中也都有應(yīng)用。
Perl中,正則表達(dá)式通常簡稱為模式。正則表達(dá)式是具有一定特征的一個(gè)模板,任意的字符串都可以與其匹配,且只有兩種匹配結(jié)果:匹配或不匹配。所以正則表達(dá)式常用于布爾上下文中,從而使其匹配結(jié)果作為布爾值返回。
模式匹配操作符
Perl中,使用模式匹配操作符“m//”進(jìn)行模式匹配操作。完整的模式匹配操作符包括關(guān)鍵詞m其后的定界符。類似于qw簡寫,可以選用任意成對(duì)且合適的符號(hào)作為定界符,且當(dāng)以斜線作為定界符時(shí),可以省略關(guān)鍵字m。
當(dāng)沒有為m//指定匹配的內(nèi)容時(shí),其會(huì)默認(rèn)匹配$_的內(nèi)容。下例是一個(gè)簡單的模式匹配:
$_="abcd";
if(/a/){print'T'}else{print'F'}??? #模式/a/會(huì)在$_中匹配a,即$_中是否出現(xiàn)了a,結(jié)果是真,所以輸出T。由于以斜線作為定界符,所以省略了斜線前的m
模式中的內(nèi)插與反斜線轉(zhuǎn)義
所有在雙引號(hào)引起的字符串中可以使用的技巧,都可以在模式表達(dá)式中使用。最主要的即反斜線轉(zhuǎn)義和模式內(nèi)插。例:
print'T'if/\n/;??? #在模式中使用反斜線轉(zhuǎn)義,匹配換行符
print'T'if/$n/;??? #在模式中使用變量內(nèi)插,匹配$n的內(nèi)容
綁定操作符
默認(rèn)情況下m//的操作對(duì)象是$_的內(nèi)容。而如果要為模式指定匹配的對(duì)象,就可以使用綁定操作符“=~”。例:
print'T'if$n=~/a/;??? #模式用于匹配$n的內(nèi)容
綁定操作符是一個(gè)優(yōu)先級(jí)相當(dāng)高的操作符,所以在一般的表達(dá)式中,如果不使用括號(hào)限定,那么就會(huì)優(yōu)先進(jìn)行模式匹配。例:
$_=$n=~/a/;??? #先進(jìn)行匹配,再將匹配結(jié)果返回并賦值給$_(返回的結(jié)果為1或undef,默認(rèn)布爾值)
元字符初步
在模式中有一類特殊字符,一般情況下其不代表本身,而是有著特殊的含義,這一類字符就稱為元字符。在下文中會(huì)出現(xiàn)各種元字符的運(yùn)用。這里將常見的元字符列舉如下:
點(diǎn)號(hào)“.”
反斜線“\”
量詞“*”、“+”、“?”
小括號(hào)“( )”
中括號(hào)“[ ]”
豎線“|”
在模式中,點(diǎn)號(hào)又稱通配符,可以用于匹配任意一個(gè)非換行符字符。例:
/a../???? #可匹配aaa、abc等
/a..d/??? #可匹配abcd、aaad等
類似于雙引號(hào)圈引的字符串,在模式中反斜線可用于反斜線轉(zhuǎn)義,也可用于將特殊的元字符轉(zhuǎn)義為其自身。例:
/\n/???#匹配換行符
/\./???#匹配點(diǎn)號(hào)
/\\/???#匹配反斜線自身
量詞初步
在模式中,量詞可以用于重復(fù)量詞前的某一部分內(nèi)容。不同的量詞代表前面條目不同的的重復(fù)次數(shù)。常用的量詞主要有三種:星號(hào)“*”、加號(hào)“+”和問號(hào)“?”。星號(hào)量詞可以將其前面的條目重復(fù)零次至多次。也就是說,星號(hào)前面的條目可以不出現(xiàn),也可以重復(fù)出現(xiàn)任意多次。類似于星號(hào)量詞,加號(hào)量詞可以將其前面的條目重復(fù)一至多次。也就是說,加號(hào)前面的條目必須至少出現(xiàn)一次才能匹配。而問號(hào)量詞的限定更為嚴(yán)格,其前面的條目只能出現(xiàn)零次或一次才能匹配,其他情況均不能匹配。例:
/a*b/??? #可匹配b、ab、aaab等
/a+b/??? #可匹配ab、aaab等,但不能匹配b
/a?b/??? #可匹配b或ab
量詞很常見的用法就是與通配符連用,可以匹配多個(gè)任意字符。例:
/a.*b/??? #匹配a與b之間任意多個(gè)字符,可匹配ab、aaab等
/a.+b/??? #匹配a與b之間至少一個(gè)字符,可匹配a-b、aaab等,但不能匹配ab
/a.?b/??? #匹配a與b之間至多一個(gè)字符,可匹配ab、a-b等,但不能匹配abbb等
通用量詞
如果上文中的三個(gè)常用量詞都不符合需要,還可以使用通用量詞。通用量詞用于說明具體的重復(fù)次數(shù)范圍,其由一對(duì)花括號(hào)和其中的數(shù)字組成,數(shù)字可以為一個(gè)或兩個(gè),中間以逗號(hào)隔開,用以說明重復(fù)次數(shù)范圍。而如果省略第二個(gè)數(shù)字但有逗號(hào),則表示重復(fù)次數(shù)無上限。例:
/a{3}/???? ?#重復(fù)三次,只能匹配aaa
/a{3,5}/??? #可匹配重復(fù)次數(shù)三次至五次的a
/a{3,}/???? #可匹配重復(fù)至少三次的a
常用的三個(gè)量詞實(shí)質(zhì)上就是通用量詞的簡寫:
{0,}???? #相當(dāng)于*
{1,}???? #相當(dāng)于+
{0,1}??? #相當(dāng)于?
模式分組
在正則表達(dá)式中,小括號(hào)作為一種元字符,其作用為對(duì)模式表達(dá)式的內(nèi)容進(jìn)行分組,從而對(duì)這一組內(nèi)容進(jìn)行整體上的處理。最常見的如對(duì)一組內(nèi)容整體上使用量詞,而不是像上文那樣僅對(duì)量詞前的一個(gè)字符使用。模式分組實(shí)質(zhì)上是利用了小括號(hào)在模式中的最高優(yōu)先級(jí)這一性質(zhì)(詳見“優(yōu)先級(jí)”),從而使分組中的內(nèi)容形成一個(gè)整體,以實(shí)現(xiàn)各種整體上的操作。例:
/ab+/???? #量詞僅對(duì)其前面的b起作用,可匹配abbb等
/(ab)+/??? #使用模式分組,量詞對(duì)(ab)起作用,可匹配ababab等
擇一匹配
在正則表達(dá)式中,有一個(gè)類似于邏輯或操作符“||”的符號(hào)“|”,稱為擇一豎線,其可用于擇一匹配。擇一匹配的意思即擇一豎線兩邊的內(nèi)容都可以嘗試進(jìn)行匹配,也就是說,如果左邊的內(nèi)容匹配失敗,還可以嘗試匹配右邊的內(nèi)容。擇一豎線是模式匹配中優(yōu)先級(jí)最低的一個(gè)元字符,所以使用時(shí)應(yīng)注意在需要的時(shí)候使用模式分組。例:
/a|b|c/???? #匹配a或b或c
/a(b|c)d/??? #匹配abd或acd
/ab|cd/???? #匹配ab或cd
字符集
前文提到,一個(gè)點(diǎn)號(hào)可以用來代表任意一個(gè)非換行符字符。而如果需要匹配的可能字符種類沒有這么寬泛,而是一組特定的字符,比如需要匹配任意一個(gè)數(shù)字,或是小寫字母等,就可以使用字符集。
字符集書寫在一對(duì)方括號(hào)內(nèi),表示所有可能出現(xiàn)的字符。字符之間不需要任何分隔。例:
/[abc]/???? #一個(gè)字符集,可匹配abc中任意一個(gè)字符一次
/[123]+/??? #字符集與量詞連用,匹配123中任意一個(gè)字符至少一次
當(dāng)字符集內(nèi)的字符是一串連續(xù)字符時(shí),如26個(gè)小寫字母或0到9這十個(gè)數(shù)字等,就可以使用連字符表示始末范圍,這樣可以大大簡化字符集的書寫。例:
[0-9]????? #所有的數(shù)字構(gòu)成的字符集
[a-zA-Z]??? #所有的大小寫字母構(gòu)成的字符集
在字符集中,有時(shí)候還需要構(gòu)造反義字符集,即除了字符集中的字符,其他都匹配??梢栽谧址_頭的地方加上脫字符“^”來構(gòu)造反義字符集。例:
/[^0-9]/????? #匹配除了10個(gè)數(shù)字以外的字符一次
/[^a-zA-Z]/??? #匹配除了大小寫字母以外的字符一次
某些字符集的出現(xiàn)頻率非常高,所以Perl為其設(shè)定了簡寫。字符集簡寫均由反斜線后接一個(gè)字母組成。常用的字符集簡寫及其一般性解釋如下:
[\w]???#單詞字符集,一般相當(dāng)于[a-zA-Z0-9_],即所有大小寫字母加上10個(gè)數(shù)字和下劃線
[\d]???#數(shù)字字符集,一般相當(dāng)于[0-9]
[\s]???#空白符字符集,一般可匹配空格,換行符,制表符等空白符
簡寫的字符集也能構(gòu)造反義字符集,且無需使用脫字符,直接將小寫字母換成其對(duì)應(yīng)的大寫字母即可。例:
[\W]???[\D]??? [\S]??? #三種簡寫字符集的反義寫法
在不引起歧義的情況下,字符集的中括號(hào)??梢允÷?,從而簡化書寫。例:
/\w+/??? #簡寫的單詞字符集與量詞連用
模式匹配修飾符初步
Perl中提供了一系列模式匹配修飾符,又稱為副詞或標(biāo)志。其可以改變一些默認(rèn)的匹配行為,從而對(duì)模式匹配起到修飾的作用。模式匹配修飾符書寫在模式表達(dá)式末尾定界符的后面,其都是由一個(gè)字母構(gòu)成。下文列舉了一些常用的修飾符及其作用,還有其他的一些修飾符會(huì)在后文中陸續(xù)提及:
/i修飾符:可進(jìn)行大小寫無關(guān)的匹配,即模式表達(dá)式中的字母可匹配小寫也可匹配大寫。例:
/abc/i??? #進(jìn)行大小寫無關(guān)的匹配,可匹配abc、ABC、Abc等
/s修飾符:可增大通配符匹配范圍,使其能夠匹配到換行符,多用于含有多行的字符串匹配。例:
/a.*b/s??? #增大點(diǎn)號(hào)匹配范圍,使其能夠匹配到換行符??善ヅ?a\nb"等
/x修飾符:允許在模式中隨意加入空白符,使其更易閱讀和理解,多用于復(fù)雜模式中。也就是說,使用了/x修飾符后,就可以隨意在模式中加入空格或者換行符來分隔,而Perl會(huì)將其忽略。此時(shí)如果要表示換行符或者空格本身,可以使用反斜線轉(zhuǎn)義,或使用空白字符集[\s]來匹配空白符。例:
/a b/x?????????????? #在模式中忽略空格,相當(dāng)于/ab/
/a
b/x???????????????? #在模式中忽略換行符,相當(dāng)于/ab/
/a\ b/x??? /a\nb/x???#使用反斜線轉(zhuǎn)義表示空格和換行符本身
如果要在一個(gè)模式中使用多個(gè)修飾符,直接將多個(gè)修飾符一起寫在末尾定界符之后即可,先后順序不限。例:
/a b/isx??? #同時(shí)使用三個(gè)修飾符
模式替換操作符
正則表達(dá)式不僅可以用于匹配文本,還可以用于直接修改文本??梢允褂媚J教鎿Q操作符“s///”來對(duì)文本進(jìn)行匹配并修改。s///操作的字符串一般要求存儲(chǔ)于變量中,而實(shí)際上,如果對(duì)一個(gè)未存儲(chǔ)于變量中的字符串進(jìn)行修改,那么修改的結(jié)果也是不能夠存儲(chǔ)的,所以這樣做沒有實(shí)際意義。
與m//類似,s///由關(guān)鍵詞s及其后面的定界符構(gòu)成。第一對(duì)定界符內(nèi)為一個(gè)正則表達(dá)式,第二對(duì)定界符內(nèi)為用于替換的字符串。s///會(huì)先對(duì)給定字符串進(jìn)行模式匹配,如果匹配成功,就會(huì)將全部的匹配內(nèi)容替換成第二對(duì)定界符中的內(nèi)容,而如果匹配失敗,則不會(huì)有任何效果。s///在未綁定變量時(shí)默認(rèn)的操作對(duì)象也是$_中的內(nèi)容,可使用綁定操作符為其指定一個(gè)操作對(duì)象。例:
s/@/>/;??? #在$_中匹配@字符,如果匹配成功,則將其替換為>
與m//類似,s///中也可使用變量內(nèi)插、反斜線轉(zhuǎn)義等功能。在默認(rèn)情況下,s///只會(huì)對(duì)其匹配到的第一個(gè)可替換部分進(jìn)行替換,然后就結(jié)束語句。也就是說,即使還有其他可以替換的部分,在默認(rèn)情況下s///也只會(huì)進(jìn)行一次替換。例:
$_=aaa;
s/a/b/;??? #此時(shí)$_會(huì)被替換為baa
s///自身返回的是成功替換的次數(shù),在沒有修飾符的情況下,返回值只能為0或1,即成功替換的次數(shù)只能為0或1次。也可以將其返回值當(dāng)作布爾值使用,用來表示替換操作是否成功進(jìn)行。例:
print while s/a/b/;??? #將s///用在布爾上下文中,進(jìn)行循環(huán)替換
while(s/a/b/){}?????? #借助while循環(huán)進(jìn)行多次替換(僅作示例,實(shí)際上無需這種寫法,詳見“全局替換”)
上文提到,s///的關(guān)鍵詞s后面也是定界符,也就是說,s后面的符號(hào)可以任意選用。但由于s///后面的定界符不止一對(duì),所以使用上較m//有所區(qū)別。如果s///的定界符選用的是類似于斜線這樣的非成對(duì)字符,即沒有左右之分的定界符,那么用法就同斜線一樣,使用三個(gè)即可。而如果選用的定界符是類似于花括號(hào)這樣的分左右的成對(duì)字符,那么定界符就需要使用兩對(duì),一對(duì)包住模式,另一對(duì)包住替換字符串。且在這種使用兩對(duì)定界符的情況下,這兩對(duì)定界符可以分別選用不同的符號(hào),可以成對(duì),也可以非成對(duì)。依據(jù)需求選用即可。例:
s#a#b#;??? #使用非成對(duì)字符井號(hào)作為定界符
s{a};???? #使用成對(duì)的花括號(hào)作為定界符
s\b\;? ? ? ? ?#定界符混合使用
s/a/b/;???? #上面的三個(gè)語句都和此寫法沒有任何區(qū)別
全局替換
上文提到,在默認(rèn)情況下,s///最多只能進(jìn)行一次替換。而如果想讓s///進(jìn)行全部可能的替換,就可以使用全局替換修飾符“/g”。
/g修飾符可以讓s///進(jìn)行所有可能且不重復(fù)的替換,這里的不重復(fù)是指:s///的每一次模式匹配都會(huì)從最近一次替換操作結(jié)束位點(diǎn)的下一個(gè)字符開始,從而避免對(duì)已被替換的內(nèi)容進(jìn)行重復(fù)替換。例:
s/a/b/g;??? #對(duì)$_進(jìn)行全局替換,將所有匹配到的a替換為b
s///的修飾符用法和m//一致,都可以同時(shí)使用多個(gè)修飾符,且直接將多個(gè)修飾符一起寫在s///的最后一個(gè)定界符之后即可,順序不限。例:
s/a/b/gix;??? #同時(shí)使用三個(gè)修飾符
無損替換
上文提到,在默認(rèn)情況下,s///會(huì)直接修改變量的內(nèi)容,而其自身返回的是成功替換的次數(shù)。而如果需要保留原字符串的內(nèi)容,且將替換后的結(jié)果作為s///的返回值返回,就可以使用無損替換修飾符“/r”。
/r修飾符可以讓s///的返回值由成功替換的次數(shù)變?yōu)樘鎿Q結(jié)果,并且不對(duì)原字符串的內(nèi)容做任何修改,從而實(shí)現(xiàn)無損替換。例:
$n=s/a/b/gr;??? #對(duì)$_進(jìn)行無損的全局替換,并將結(jié)果返回并賦值給$n,$_中的內(nèi)容不會(huì)改變
櫻雨樓
完成于2016.1.19
最后修改于2016.2.1