捕獲組與反向引用
在正則表達式中,圓括號的一大作用是進行模式分組,而其還有另一個非常重要的作用,即定義捕獲組。捕獲組是由捕獲圓括號構(gòu)建的模式分組,其中的內(nèi)容可以被正則表達式捕獲并進行反向引用。反向引用的意思即引用某捕獲組中已經(jīng)捕獲到的某些內(nèi)容,其簡單寫法為反斜線加捕獲組編號。例:
/(..)\1/??? #使用圓括號構(gòu)造一個捕獲組,并反向引用
上例中,圓括號構(gòu)建了一個捕獲組,首先由通配符進行匹配,如果匹配到了ab,那么反向引用的字符就又是ab,即這個模式匹配abab。類似的,如果通配符匹配到了bb,那么模式就匹配bbbb。即反向引用的作用就是再次重復其對應捕獲組中匹配到的全部內(nèi)容。反向引用無需緊跟其對應捕獲組,而是可以用在任何地方。
捕獲組的編號較為簡單,只需要從左向右根據(jù)左括號的次序來編號即可。下例為一個較復雜的捕獲組:
/((a)(b)\3\2)\1/??? #通過數(shù)左括號來確定捕獲組編號
上例中,通過數(shù)左括號可知,最外圍的是1號捕獲組,a和b所在的兩個捕獲組分別是2、3號捕獲組。所以這樣的反向引用可以匹配abbaabba類型的字符串。
\g{N}寫法與相對反向引用
在上文的反向引用寫法中,由于捕獲組編號沒有任何的界限標識,所以很容易出現(xiàn)歧義。例:
/(.)\11/??? #引起歧義的捕獲組
很明顯,這里反向引用的是\1,但由于Perl的最長且合理邏輯,這里的代碼會被認為是反向引用\11,這就是由于捕獲組編號沒有任何界限標識所導致的歧義。從Perl 5.10開始,可以使用一種新的寫法來進行反向引用,即\g{N}寫法,花括號內(nèi)書寫的是捕獲組編號,從而使捕獲組編號具有了界限標識,消除了可能產(chǎn)生的歧義。例:
/(.)\g{1}1/??? #消除了花括號內(nèi)的捕獲組編號1與后面的字符1之間的歧義
使用\g{N}寫法后,還可以使用一種新的捕獲組編號方式來進行反向引用,即相對反向引用。相對反向引用均使用負數(shù)作為捕獲組編號,其編號方法不再是以從左向右數(shù)左括號的方式進行的絕對編號,而是從相對反向引用位點開始向前數(shù)捕獲組左括號,捕獲組與相對反向引用位點之間的距離就是該捕獲組的編號。例:
/(.)(.)\g{-1}\g{-2}/??? #第一個相對反向引用對應的捕獲組就是其左邊的組,第二個對應的是從其位點向左數(shù)第二個組,即從左數(shù)第一個組,可匹配abba類型字符串
這種根據(jù)引用位點進行的相對編號較之于絕對編號,其最大的優(yōu)點就在于不太容易因捕獲組的數(shù)量和位置變動而導致所有的捕獲組編號全部改變。所以在實際的應用中,應根據(jù)實際需求選擇合適的編號及反向引用方式。如下例:
/(.)(.)\2\1/=> /(.)(.)(.)\3\2/?????????????? #使用絕對編號的情形,當增加一個捕獲組時,1、2號捕獲組編號全部改變
/(.)(.)\g{-1}\g{-2}/=> /(.)(.)(.)\g{-1}\g{-2}/??? #使用相對編號的情形,由于增加捕獲組并沒有改變引用位點與捕獲組的相對距離,所以編號不改變
捕獲變量
使用捕獲組捕獲到的內(nèi)容不僅可以用于反向引用,其還會被保存到捕獲變量中,從而可以對這些捕獲變量進行更高級的操作。捕獲變量都是標量變量,在默認情況下,其以數(shù)字進行命名,數(shù)字就是該捕獲組的絕對編號,這種數(shù)字變量名稱是Perl中的一類特殊的變量名。例:
print$1 if/(.)/;??? #如果匹配成功,就輸出捕獲變量$1的內(nèi)容,也就是模式中絕對編號為1的捕獲組捕獲到的內(nèi)容
捕獲變量可以對一個字符串中的數(shù)據(jù)進行精確定位、篩選、提取、修改等,是正則表達式的核心內(nèi)容之一。例:
s/(.*)/\U$1/;??? #匹配任意字符,并使用s///與\U將捕獲到的內(nèi)容全部轉(zhuǎn)為大寫,這樣的操作類似于uc函數(shù)
捕獲變量的存續(xù)期
通常情況下,捕獲變量的值能夠存續(xù)到下一次成功匹配為止。也就是說,一次成功的匹配會將所有捕獲變量的值重置為新值,而失敗的匹配不會改變捕獲變量的值,其值仍然是上一次成功匹配時得到的。下例為一個示例程序:
/(a)/;/(b)/;??? #假設/(a)/匹配成功,那么當/(b)/又一次匹配成功后,$1的值就會被重置為b,否則其值仍然為a
需要注意的是,當下一次匹配成功時,之前的所有捕獲變量都會被重置,而不單單是在新的匹配中用到的捕獲變量。例:
/(.)(.)/;
/(.)/;??? #如果匹配成功,那么上一次匹配中的$1和$2都會被重置,$1會被重置為新值,而$2會被重置為undef
命名捕獲
每一個捕獲組都有其自己獨立的名稱,而事實上,捕獲組的絕對編號就是該捕獲組的默認名稱。而這種默認名稱由于使用的是絕對編號,所以在使用時存在種種不便。從Perl 5.10開始,可以對捕獲組進行命名,使每一個捕獲組擁有其獨立的,且不受其他捕獲組影響的名稱,從而避免了使用絕對編號所帶來的不便。
命名捕獲使用特殊哈?!?+”來存儲捕獲組的名稱與其捕獲到的內(nèi)容。捕獲組名就是%+中的各個哈希鍵,而其對應的值就是各個捕獲組捕獲到的內(nèi)容。將“?<...>”加在捕獲組前括號之后即可對捕獲組命名,尖括號中書寫的就是該捕獲組的名稱。例:
/(?.*)/??? #對捕獲組(.*)命名
命名捕獲用到了問號在正則表達式中的第三種用法,而前兩種分別為表示問號本身和作為量詞使用,下文中還會出現(xiàn)問號的另外兩種用法。
當提取一個已命名的捕獲組捕獲到的內(nèi)容時,根據(jù)其哈希鍵,即該捕獲組的名稱提取對應的哈希值即可。例:
print"$+{a} $+" if /(?.)(?.)/;? ? #如果匹配成功,就輸出兩個捕獲組捕獲到的內(nèi)容,即存儲在%+中的兩個哈希值
對捕獲組進行命名后,捕獲組的名稱就由絕對編號變?yōu)榱似洫毩⒌牟东@組名,所以在反向引用的\g{N}寫法中,原先使用的絕對編號也要變?yōu)橄鄳牟东@組名(仍然使用絕對編號也可以,但是這樣無意義)。例:
/(?.)\g{word}/???#對命名的捕獲組進行反向引用
命名后的捕獲組由于使用了獨立的捕獲組名,在反向引用時便不再受其他捕獲組變動造成的影響,從而使代碼更加易于維護。下例僅為一個示例:
/(?.)\g{name}/ =>/((.)(?.))\g{name}/??? #在其他捕獲組發(fā)生變動后,反向引用仍然使用該捕獲組獨立的名稱
需要注意的是,命名捕獲并不會改變捕獲變量的存續(xù)期,其存續(xù)期與使用標量變量的情況是一致的。當下一次匹配成功時,用于存儲捕獲組鍵值對的特殊哈希%+會被整個重置為新哈希,其中存儲了新的鍵值對。下例可用于驗證:
print keys%+ if /(?a.)/;? ? #如果匹配成功,那么鍵列表就是(a)
print keys%+ if /(?b.)/;??? #如果再一次匹配成功,那么%+會被整個重置為新哈希,其鍵列表為(b)
非捕獲組
到目前為止,在代碼中使用的所有圓括號都是捕獲圓括號,即這種圓括號的作用不僅是進行模式分組,還會同時構(gòu)造一個捕獲組,用于捕獲匹配到的內(nèi)容。
在正則表達式中,問號的第四種用法就是構(gòu)造不捕獲圓括號,而這種由不捕圓括號構(gòu)建的模式分組就稱為非捕獲組。不捕獲圓括號相對于普通的圓括號,其功能為進行純粹的模式分組而不會構(gòu)建捕獲組。非捕獲組可以用在許多僅需要模式分組而不對其進行捕獲的情況中。將“?:”書寫在捕獲組前括號之后即可表示一對非捕獲圓括號。例:
print$1 if/(?:.)+(.)/;??? #第一對圓括號構(gòu)建的是非捕獲組,只有分組功能而不參與捕獲,所以后面的圓括號才是1號捕獲組,其捕獲到的內(nèi)容存儲于$1中
由上例可見,非捕獲組可以安全地被添加到現(xiàn)有模式中而不會影響其他捕獲組的編號,這對于模式的修改與維護是十分方便的。
自動捕獲變量
Perl中自帶有三個自動捕獲變量,可以對模式進行自動捕獲,其使用時無需捕獲圓括號,且其所有性質(zhì),如捕獲變量的存續(xù)期等,均與普通的捕獲變量完全一致。這三個自動捕獲變量分別為“$&”、“$`”和“$'”。第一個自動捕獲變量存儲的是整個正則表達式在原字符串中匹配到的區(qū)段,第二個和第三個自動捕獲變量存儲的分別是原字符串中匹配區(qū)段前與匹配區(qū)段后的所有內(nèi)容,即正則表達式在原字符串中找到匹配區(qū)段之前略過的部分與匹配后剩余的部分。如果將這三個變量的內(nèi)容連接起來,就一定能得到與進行匹配的原字符串一模一樣的一個字符串。例:
$_='abc';
print"($`)($&)($')" if /b/;??? #輸出(a)(b)(c),分別對應了這三個變量中的內(nèi)容
絕對首尾錨位
在默認情況下,正則表達式會從給定字符串的開頭開始匹配,如果匹配失敗,就不斷向后順移一個字符繼續(xù)匹配,直到匹配成功為止。而錨位可以讓正則表達式僅在字符串的某一個固定位置進行匹配,如字符串的開頭、末尾或中間的某一個單詞。
\A錨位一般書寫在模式的開頭,表示后面的模式只匹配給定字符串的絕對開頭。例:
$_='abba';
print if /\Ab/;??? #模式只能在$_的開頭匹配b而不會向后順移,所以這里匹配失敗
\z錨位的用法與\A錨位類似,其一般書寫在模式的最后,表示這里需要錨位到字符串的絕對末尾。為方便起見,還有一個類似于\z的\Z錨位,其可以進行忽略末尾換行符的末尾錨位,即如果字符串末尾有換行符,就會被\Z忽略,從而將錨位定位到換行符之前的那個字符。由于讀取的文件內(nèi)容的末尾常含有換行符,所以這種錨位很方便且常用。例:
$_="ab\n";
print if /b\z/;??? #絕對末尾錨位,只在$_的末尾匹配b,而由于其末尾是換行符,所以匹配失敗
print if /b\Z/;??? #忽略換行符的末尾錨位,匹配成功
行首尾錨位
如果一個字符串的內(nèi)容較長,且其中間有若干換行符將其內(nèi)容分為多行,那么此時就可以對這個字符串每一行的首尾進行錨位,即行首錨位和行尾錨位。
在Perl 4中,“^”和“$”相當于上文中的\A與\z,并且這兩個符號現(xiàn)在也可以發(fā)揮同樣的功能,但這是不安全也不推薦的寫法。在Perl 5中,這兩個符號一般用于行首尾錨位,其需要與/m修飾符連用。/m修飾符的作用相當于一個開關,用來打開行首尾錨位功能。此功能打開后,^與$就能對一個字符串中每一行的開頭和末尾進行錨位,而不像\A與\z那樣只能對一個字符串的絕對開頭和末尾進行錨位。進行行末尾錨位時,$會忽略行尾換行符。例:
$_="ab\ncd\n";?? ??#包含兩行的字符串,第一行為ab\n,第二行為cd\n
print'Z' if /b\Z/;???? #進行忽略換行符的末尾錨位,只能匹配d,匹配失敗
print'$' if /b$/m;??? #使用/m修飾符打開行首尾錨位功能,并使用$進行行末錨位。所以會匹配到第一行行末的b
單詞錨位
錨位并不局限于整個字符串的首尾,其也可以是字符串中某一個單詞的首尾。這里的單詞指的是一組由字符集[\w]組成的字符串,單詞錨位就是對這些字符串的首尾,即單詞邊界進行的錨位。
單詞由連續(xù)的\w字符組成,所以任何位于[\W]字符集中的字符,外加一個字符串的絕對開頭和絕對末尾,都可以作為單詞邊界。每一個單詞的兩側(cè)都必定各有一個邊界,即在一個字符串中,不存在沒有開頭或沒有結(jié)尾的一個單詞,所以一個字符串中的單詞邊界一定是偶數(shù)個,且至少為兩個。
單詞錨位分為兩種,單詞邊界錨位“\b”和非單詞邊界錨位“\B”。\b可以書寫在模式字符串中某一個單詞的開頭、結(jié)尾或兩邊都書寫,用來限定匹配單詞的首尾。例:
$_="a-bc-d";?????#包含三個單詞的字符串,a、bc和d
print if/\bb\b/;??? #同時錨位單詞b的兩個邊界,所以只能匹配單詞b,匹配失敗
print if/\bb/;????? #錨位b作為單詞開頭,即匹配的單詞必須以b開頭,能夠匹配b、bc等,匹配成功
print if/b\b/;????? #錨位b作為單詞結(jié)尾,即匹配的單詞必須以b結(jié)尾,能夠匹配b、ab等,匹配失敗
非單詞邊界錨位\B的用法和\b一致,但其功能與\b完全相反。\B進行的是不能成為單詞邊界的錨位,即被錨位的模式字符串不能作為單詞邊界,而只能作為某一單詞的中間部分達成匹配。例:
$_="a-bc-d";?????#包含三個單詞的字符串
print if/\Bb\B/;??? #b不能作為兩個單詞邊界,可匹配abc、bbb(第二個b匹配)等,匹配失敗
print if/\Bb/;????? #b不能作為單詞開頭,可匹配abc、ab等,但不能匹配bc等,匹配失敗
print if/b\B/;????? #b不能作為單詞結(jié)尾,可匹配bc、bb(第一個b匹配)等,但不能匹配ab等,匹配成功
優(yōu)先級
正則表達式中有許多的元字符,如同操作符一樣,這些元字符也存在優(yōu)先級。正則表達式的優(yōu)先級表分為五個等級,大致內(nèi)容如下:
最高優(yōu)先級的為圓括號,包括具有各種功能的圓括號,如捕獲組,非捕獲組,命名捕獲組等。括號的最高優(yōu)先級保證了其能夠進行分組、捕獲等重要操作而不受其他元字符的影響。
第二優(yōu)先級的為量詞,包括三個符號量詞與通用量詞。量詞緊密地與其前面的分組或單個元素相連,從而進行重復。
第三級為錨位和序列。錨位用于固定匹配位置,而序列指的是單個字符與字符之間的連接,如abc這三個字符之間的連接。也就是說,錨位也可以看作是一種特殊的序列,錨位與字符之間的連接(如\babc\b中\(zhòng)b與a、c與\b之間)與序列中字符之間的連接(如\babc\b中ab、bc之間),其緊密程度是同級的。
第四級為擇一豎線“|”。這是一個優(yōu)先級很低的符號,比較重要的意義在于其優(yōu)先級低于序列,這樣就可以使一個單詞作為一個整體參與擇一匹配,而不會被擇一豎線拆成單個字符。如擇一匹配:/ab|cd/,由于序列的優(yōu)先級更高,所以是ab與cd而不是b與c參與了擇一匹配,而如果加上括號:/a(b|c)d/,由于括號的優(yōu)先級高于序列,從而使得b與c參與了擇一匹配。
最低優(yōu)先級的稱為原子。原子構(gòu)成了正則表達式中大多數(shù)最基本的內(nèi)容,也可以理解為除了上述四個優(yōu)先級中出現(xiàn)的內(nèi)容,其他部分均屬于原子。原子主要包括字符、字符集、通配符以及反向引用等。
split操作符
split操作符是一個使用到了正則表達式的操作符,其可以根據(jù)給定模式將一個字符串進行拆分,并返回拆分后形成的列表。
split操作符包含兩個參數(shù),第一參數(shù)為一個正則表達式,又稱為拆分模式,第二參數(shù)為需要拆分的字符串。拆分模式會在指定字符串的開頭不斷向后進行匹配,每一次匹配成功,該處就會成為當前拆分字段的結(jié)尾與下一拆分字段的開頭,而整個匹配區(qū)段會作為拆分位點而被去除,所以在最終拆分的結(jié)果中不會出現(xiàn)任何匹配拆分模式的區(qū)段。例:
$n='a;b;c';
@m=split/;/,$n;??? #以分號作為模式拆分$n的內(nèi)容,所有的分號都將作為拆分位點而被去除。拆分結(jié)果為(a,b,c)
如果省略split的第二參數(shù),則其默認對$_中的內(nèi)容進行操作。而如果省略其全部參數(shù),則就相當于split/\s+/,$_;,這是一種很常見的用法,可以匹配至少一個連續(xù)空白符并將其作為$_中內(nèi)容的拆分位點。例:
@m=split/;/;??? #相當于split/;/,$_;
print split;????? #相當于split/\s+/,$_;
除了/\s+/拆分模式,split還有一個很常用的拆分模式,即空字符串拆分模式。由于空字符串可以匹配任意兩個字符之間的間隙,所以這樣的操作會將整個字符串中的每一個字符全部拆分,返回由許多單個字符組成的列表。而這種拆分模式屬于split的特殊用法之一,在書寫上可以省略拆分模式的定界符。例:
$_='abcd';
@n=split'';??? #以空字符串拆分$_中的內(nèi)容。拆分結(jié)果為(a,b,c,d)
split操作符在使用時需要注意兩點,出現(xiàn)這兩點的情況都比較罕見,所以不會構(gòu)成太大的影響。第一:如果spilt的拆分模式匹配到一個以上連續(xù)的拆分位點,那么在返回的列表中就會出現(xiàn)空字符串,空字符串的數(shù)量為這些拆分位點的數(shù)量減一,且如果這些拆分位點位于字符串開頭,那么空字符串的數(shù)量就是拆分位點的數(shù)量,而如果這些拆分位點位于字符串末尾,那么由其形成的空字符串就會被全部舍棄。下例為一個示例:
$_=',,,a,,,b,,,';
$n=split/,/;??? #最終返回的列表為('','','','a','','','b')
第二:在拆分模式中需要避免使用捕獲圓括號,而應使用不捕獲圓括號,否則會出現(xiàn)問題。由于拆分模式往往都十分簡單,所以這種情況很罕見。
join函數(shù)
上文中的split操作符可以用于拆分字符串并返回列表,而join函數(shù)的功能與其相反,可以將一個列表中的所有元素都連接在一起,并返回一個標量。join函數(shù)也包含兩個參數(shù),第一參數(shù)又稱為膠水,其可以是任意的一個字符串,膠水會被涂在每兩個列表元素之間,從而連接所有的列表元素,第二參數(shù)是需要進行連接的列表。例:
print join'-',1..5;??? #以“-”作為膠水連接參數(shù)列表,返回連接后的字符串并輸出,輸出結(jié)果為1-2-3-4-5
由上例可見,膠水只會出現(xiàn)在每兩個相鄰列表元素之間,所以膠水的數(shù)量總是比列表元素的數(shù)量少一,這也意味著進行連接的列表元素至少需要兩個,否則不會有任何效果。
常用的一種膠水為空字符串,使用其作為膠水就可以無縫連接列表元素,例:
print join'',1..5;??? #使用空字符串作為膠水無縫連接列表元素,輸出12345
join函數(shù)也可以與split連用,如下例:
$_='a-b-c-d';
print join'',split/-/;??? #以split的返回值作為join的第二參數(shù)。首先以“-”作為拆分位點,將$_拆分為列表(a,b,c,d),再使用join對其進行無縫連接,最終輸出abcd
列表上下文中的m//與全局匹配
m//一般用于布爾上下文中表示匹配結(jié)果,而在列表上下文中,m//也同樣能發(fā)揮許多強大的功能。在列表上下文中使用m//時,如果匹配成功,那么其返回的是模式中所有捕獲變量組成的列表,而如果匹配失敗,則會返回空列表。而由于捕獲變量在實際運算時會被替換為變量當前值,所以m//返回的內(nèi)容也可以理解為就是每一個捕獲組捕獲到的內(nèi)容形成的列表。例:
($n)=/(.)/;??? #在列表上下文中返回該捕獲組捕獲到的內(nèi)容并賦值
前文提到,/g修飾符可用于s///進行全局替換,類似的,/g修飾符也可用于m//進行全局匹配,其匹配方式與s///一致,均為進行不重復的匹配。每次成功匹配時,m//就會返回當前所有捕獲組捕獲到的值,作為最終返回的列表元素的一部分。例:
$_='abcd';
@n=/(.)(.)/g;??? #進行全局匹配。第一次匹配成功會返回a和b,即模式中兩個捕獲組分別捕獲到的值。第二次匹配成功會返回c和d,所以最終返回的列表為(a,b,c,d)
在列表上下文中使用m//也可以理解為使用反向的split。split的拆分模式指定的是字符串中想要去除的部分,而m//中的捕獲組指定的是字符串中想要留下來并返回的部分。例:
$_='a-b-c-d';
@n=split/-/;????? #拆分模式指定的是去除所有的連字符
@m=/(\w+)/g;??? #捕獲組指定的是需要留下并返回每一個匹配的單詞
在列表上下文中使用m//的另一個重要功能就是可以在模式匹配成功的同時將捕獲變量的值存儲到外部變量中,從而避免因捕獲變量的存續(xù)期而導致的問題,也可以使用這種方式達到類似于修改捕獲變量名稱的效果。這樣的操作就相當于在匹配成功的同時將捕獲變量拷貝到外部變量中,從而在接下來的任何時候都可以對捕獲的內(nèi)容進行處理。例:
($n,$m)=/(\w+)\W+(\w+)/;???#將捕獲的內(nèi)容拷貝到外部變量中
非貪婪量詞
到目前為止,程序中使用的所有的量詞都是貪婪量詞。貪婪量詞在匹配時會匹配盡可能長的字符串,然后再進行回溯動作以實現(xiàn)整體模式匹配。其匹配過程描述如下:
$_='abcdefg';
print if/a.*b/;
這里的星號是一個貪婪量詞,其會匹配盡可能長的字符串。而由于通配符可以匹配任意非換行符,所以在星號量詞的作用下,通配符的匹配區(qū)段會從b一直到g。然后由于需要對模式剩下的b進行匹配,正則表達式會進行回溯動作,不斷縮短通配符的匹配區(qū)段,然后測試是否匹配成功。上例中,直到通配符的匹配區(qū)段變?yōu)榭兆址?,才能使整個模式匹配成功。
與貪婪量詞的匹配過程相反,非貪婪量詞會匹配盡可能短的字符串。在貪婪量詞后加一個問號即可將這個量詞變?yōu)榉秦澙妨吭~,對于通用量詞也是一樣,將問號加在右花括號后即可,這是問號在正則表達式中的第五種用法。非貪婪量詞的匹配過程描述如下:
print if/a.*?g/;
這里的“*?”是非貪婪星號量詞,其會匹配盡可能短的字符串,也就是從空字符串開始匹配。然后由于需要對g進行匹配,正則表達式會進行回溯,不斷加長非貪婪量詞作用下的通配符的匹配區(qū)段,直到將匹配區(qū)段加長到b至f,達成匹配。
從上例可以看出,貪婪量詞與非貪婪量詞只是在匹配過程上差異較大,但僅從匹配成功與否的角度上看,這二者的結(jié)果一定是一致的。
貪婪量詞與非貪婪量詞由于匹配過程的不同,其導致的差異主要有以下兩點:第一為匹配效率。由于貪婪量詞會匹配盡可能長的字符串,所以當最終的實際匹配區(qū)段很短,而進行匹配的字符串又很長時,正則表達式就會進行大量的回溯動作以縮短量詞作用下的匹配區(qū)段,同樣,非貪婪量詞在實際匹配區(qū)段很長時亦如此,這會降低正則表達式的效率,所以在實際的應用中應合理選擇最合適的量詞。
第二點為其最主要的差異所在,即最終匹配區(qū)段的長度不同。舉例如下:
$_='fredfredfred';
s/f.*d/barney/g;???? #使用貪婪量詞進行匹配的情況。首先在量詞的作用下通配符一直匹配到字符串末尾,然后回溯一次即達成匹配,其匹配區(qū)段為整個字符串。所以替換結(jié)果為barney
s/f.*?d/barney/g;??? #使用非貪婪量詞進行匹配的情況。通配符的匹配區(qū)段由空字符串開始回溯,直到第一個e便達成第一次匹配。所以這種情況下一共會匹配三次,每一次的匹配區(qū)段都是fred,替換結(jié)果為barneybarneybarney
智能匹配
智能匹配是Perl 5.10.1的新功能,其會根據(jù)智能匹配操作符“~~”兩邊操作數(shù)的數(shù)據(jù)類型自動判斷進行的操作。智能匹配操作符的操作數(shù)可以為直接量、標量變量、數(shù)組變量、哈希、正則表達式等。一般情況下,智能匹配操作符兩邊的操作數(shù)沒有左右之分,也就是說,如果將兩個操作數(shù)調(diào)換位置,對操作符是沒有任何影響的。智能匹配操作符可以進行的常見操作列舉如下:
%a~~%b???? #哈希鍵是否相等
@a~~@b??? #數(shù)組是否相等
%a~~@b???? #是否至少有一個哈希鍵在數(shù)組中
'a'~~%b????? #是否存在a哈希鍵(此用法不可顛倒順序)
%a~~/b/???? #是否至少有一個哈希鍵匹配給定模式
@a~~/b/???? #是否至少有一個數(shù)組元素匹配給定模式
$a~~/b/????? #模式匹配
智能匹配的用法示例如下:
use5.10.1;???????? ?#啟用Perl5.10.1
print'T'if %a~~%b;?? ?#判斷%a與%b中的哈希鍵是否一致
櫻雨樓
完于2016.1.24
最后修改于2016.2.3