[PERL] 15-進階比對 #2--使用更多修飾子

URL Link //n.sfs.tw/11783

2017-09-20 16:46:09 By 張○○

在前面有提到過樣式後面的修飾子 'g',接下來深入探討更多的修飾子。

不分大小寫比對

使用 'i' 修飾子可以在比對時忽略大小寫,i是ignore的意思,這個只會忽略英文字母的大小寫。

$str = "When and how is John doing?";
if( $str =~ /when/i ){
  print $& ."\n"; #When
}

第2行 多了一個 i作修飾子,所以 When會和when比對成功並傳回'When'

 

中文字的比對

中文字的比對和非中文的比對相同,可以直接把中文字串放入即可,perl會自動判斷編碼,沒什麼問題。若要強調比對 utf-8編碼(其實是unicode)的話,可以加上 'u' 或是 'a' 的修飾子,這兩個的差異僅在於 'a'會把ascii的字元就視為ascii的字元,而不會再轉成unicode比對 [1]

$str = "這場探討未來網路發展的世界級會議,最近剛於瑞士日內瓦落幕。
會議中,除了討論美國政府最近收回網路中立成規的決定,
對數位媒介演進太過迅速,可能造成保存問題的憂慮。";
if( $str =~ /數位媒介/a ){
  print $& ."\n"; # 數位媒介
}

第1~3行 這個字串分成三行,在每個行尾都有隱藏的 '\n'字元
第4行 使用了a修飾子指定把除了ascii的字元外的字元都視為unicode字元。

由於PERL會自動判斷編碼,事實上就算省略了這個a也能正確的判斷,但為了避免不必要的意外,遇到中文字還是建議加上。

 

比對的內容含有換行時,把換行也考慮進來

在上面的範例中,字串可能因為換行的關係而切斷,在比對時就會被忽略導致非預期的結果,舉例來說,下面字串中「網路」兩個字可能因為文章的寬度緣故被拆成兩行,實際上網路兩字中間還多了一個換行\n的符號:網\n路

$str = "這場探討未來
發展的世界級會議";

假設我們拿來比對字串「網路」,就會發現比對失敗。為了增加比對的正確性,比對時也要把可能被拆開的字串進行判斷:

$str = "這場探討未來網
路發展的世界級網路會議";
if( $str =~ /網\n?路/a){
  print $& ."\n";
}

第3行 比對字串中網路兩字中間加了一個\n?,代表判斷換行的有無。

結果


中文字麻煩的地方,也可以說是方便的地方,就是可以斷在任何地方,如果是二個字的詞就只有一種斷法,三個字的詞就會有三種斷法,n個字的詞就會有2(n-1)-1種斷法,比較偷懶的比對就是把所有的換行都先置換掉再來比對,缺點是內容很長會不知道這到底是原文的哪裡?因為換行都被抽掉,位置是抽掉後的結果。不然就是每個字和字中間都加上'\n?' 來作樣式,因為這是門困難的科學,所以略過不提。

 

一個unicode中文字代表三個字元

中文字的比對要注意,一個unicode中文字代表三個字元,例如:

$str = "這場探討未來長頸鹿存活的會議";
if( $str =~ /長.鹿/a){ print "比對成功"; }

在這範例中是不會比對成功的,除非你把'.'改成'.{3}'

if( $str =~ /長.{3}鹿/a){ print "比對成功"; }

 

把換行視為一個字元

使用 's' 修飾子可以在比對時把換行也當成一個字元來處理,沒有加s的話,比對任何一個字元 '.' 會忽略換行。

$str = "John is a boy, Mary is
a girl. They are friends.";
while( $str =~ /is.a/sg){
  print $& ."\n";
}

說明

第3行 修飾子用's'讓換行可以比對成功,在while中要加入修飾子'g'以免造成無窮迴圈。

結果

is a
is
a

如果上面沒加上 修飾子's',比對出來結果只會有一個:

is a

把字串視為多行來比對

使用 'm' 修飾子可以在比對時把換行也當成一個字元來處理,這對多行的文比對很有用。這時候代表開始的記號'^'和結束的記號'$'就會判斷每一行的頭和尾,如果沒加m的話,就只會判斷一開始和結束。

$str = "Sweater costs 200 dollars
Shirt is 300 dollars
Pants are 400
Stockings are 100 dollars";

while( $str =~ /\d+ dollars$/g){
  print $& ."\n";
}

結果

100 dollars

上面的例子中,因為在樣式中比對出行尾有 "數字 dollars"的內容,所以會把整個字串中的換行算成字串的一部分。

如果加上了 'm' 修飾子,在判斷時就會每個換行都當成一行來判斷,同樣的,在while中要加入修飾子'g'以免造成無窮迴圈。

while( $str =~ /\d+ dollars$/mg){

結果

200 dollars
300 dollars
100 dollars

Perl的修飾子很多,剩下的到取代章節再來談。

上一篇 14-進階比對 #1--取回比對內容
回到目錄 01-撰寫第一隻PERL程式
下一篇 16-字串取代和置換

參考資料

[1] https://perldoc.perl.org/perlre.html