PERL的字串比對置換非常的強大也複雜,常容易搞錯
字串的取代語法
s 是功能代號 substitute的意思
原來的字串和目的字串都能使用正規表達式
修飾子能讓取代得到更多彈性
單筆取代
把Who取代為What
$str = "Who are you? Who is he?"; $str =~ s/Who/What/; print $str; # What are you? Who is he?
第2行 使用比對運算子'=~'來作字串的取代,如果寫成等於 '=' 就不會有任何結果。
這樣的結果只會取代第一個發現的目標。
大量取代
如果要一次取代多組比對結果,可用前面介紹過的 'g' 修飾子:
這樣一次就能全部取代
大量取代有一個問題就是想知道到底取代多少筆,有一個技巧能取得取代的個數:
print $n; # 取代的個數
取代時使用函數變換
s/// 裡面的「目的字串」是可以放入函式的,例如以下幾個常用的函數:
uc($str) 把$str 全轉成大寫
lc($str) 把$str 全轉成小寫
ucfirst($str) 把$str 第一碼轉成大寫
要使用函式還得加上 'e' 修飾子才行,例如把下面的句子中每個單字w字首大寫
$str = "What a wonderful wonderful world."; $str =~ s/w\w+/ucfirst($&)/ge; print $str;
說明
第2行 樣式w\w+是指w開頭的字後面跟著\w+字元(a-zA-Z0-9_);ucfirst($&) 中的 $&是比對的結果
結果
What a Wonderful Wonderful World.
上面的 'e'修飾子不加的話會變成一般的字串。
函數也可以自己寫,例如我寫一個 'l' 轉成 '1'、'o' 轉成 '0'、'd'轉成'6'的函數 trans2pwd。
sub trans2pwd{ my $s= shift; $s =~ tr/lod/106/; return $s; } $str = "What a wonderful wonderful world."; $str =~ s/\w+/trans2pwd($&)/ge; print $str;
說明
第1~5行 自訂函數trans2pwd
第3行 tr///這個是清單的取代,可以快速的作字元替換,接下來會談到。
結果
What a w0n6erfu1 w0n6erfu1 w0r16.
不得不說PERL實在太厲害了!
改變區隔字元
在取代中常常會遇到特殊字元需要作置換,例如網址 http://old.example.com/ 要換成 http://n.sfs.tw/old
這樣的寫法肯定是錯的
$str =~ s/http://old.example.com//http://n.sfs.tw/old/;
你必須要在 '/' 和 '.' 加上脫逸字元
$str =~ s/http:\/\/old\.example\.com\//http:\/\/n.sfs.tw\/old/;
這時你可以換掉區隔字元 '/' 為 '|',像這樣:
$str =~ s|http://old\.example\.com/|http://n.sfs.tw/old|;
這個區隔字元可以換成幾個不造成你干擾的字元都可以
s|原字串|新字串|
s#原字串#新字串#
s!原字串!新字串!
s(原字串)(新字串)
s{原字串}{新字串}
看起來簡潔多了。
使用清單來取代
上面的 s///是字元取代,如果想一次多項取代,可以使用PERL提供的清單取代 tr///
其中的選項只有三種
c Complement the SEARCHLIST. <== 清單沒寫到的就補給他右邊清單的最後一個字元
d Delete found but unreplaced characters. <== 對照表中沒有的項目就刪掉
s Squash duplicate replaced characters. <== 連續重覆出現的字壓成一個
大小寫互換範例
如果要大小寫互換,對PERL來說容易
$str = "What a Wonderful Wonderful World."; $str =~ tr/a-zA-Z/A-Za-z/; print $str;
清單互換可以這樣看成同色的互換,所以兩邊組數要一樣,以免產生非必要的結果。
tr/a-zA-Z/A-Za-z/
使用別名y
tr/// 還有一個別名,叫作 y/// 所以要把數字0和9互換,可以寫成:
$doc =~ y/09/90/;
y///和m//一樣,可以把邊界分隔字元換掉:
$doc =~ y|09|90|;
右清單數量不足
如果清單左右的數量不同,那麼PERL自動會補右邊清單最後一個字元,例如:
tr/a-zA-Z/A-Za-z/
如果只寫
tr/a-zA-Z/A-Z/
右邊清單少了一項,會發生什麼事?其實預設會補右邊清單A-Z的最後一個字元'Z',也就是說,左邊大寫的A-Z全換成'Z'
$str =~ y|a-zA-Z|A-Z|;
結果
ZHAT A ZONDERZUL ZORLD IS TO ZZ.
使用 \w \d等集合字元沒有效果
清單需用列的,如果用集合字元 \d \w \W 等等不會有效果,例如
$str =~ tr/\w/0-9/;
沒有作用,那是因為 '\' 字元在清單中是沒有作用的,只被當成一個普通的脫逸 '\' 字元。如果要取代的是反斜線本身,就得寫成 '\\'
使用選項c
選項c的效果是指如果左清單沒列到的,就全補右清單的最後一個字元,例如:
$str =~ y|a-zA-Z|A-Z|c;
結果
WhatZaZWonderFulZWorldZisZtoZBEZ
左清單沒列到的 空白' '和 點'.'都換成大寫的Z了,原來該作的置換沒有做!其實就是例外處理的意思:
使用選項d
選項d的效果是指如果右清單沒列到的,就刪掉,例如:
$str = "what a WonderFul World is to BE.";
$str =~ y|aeiou|AEI|d;
結果
whAt A WndErFl Wrld Is t BE.
其中aei三個字元換成AEI,但是ou這兩個字元沒有批配的清單內容,就被刪了。
使用選項s
重覆出現的字元壓成一個,例如:
$str = "Wooooo! good cheese~~";
$str =~ y|oe |oe |s;
結果
Wo! god chese~~
重覆出現的 'o', 'e' ,' ' 換成單一一個 'o', 'e' ,' ' ,這個方法可以快速的移掉多餘的空白。
利用清單來計算字元數
清單可以拿來快速的計算字元數,只要善用PERL的邏輯就好。
如果置掉時,把自己換成自己,就知道有幾個字元了。例如計算數字出現個數:
$n= $doc=~ tr/0-9/0-9/;
print $n; #22
左清單的0-9你可以換成任何想算的字元
在取代中使用變數
有些情況是想動態的讓樣式變化,無論是 s///或是tr/// 如果要用變數,寫成這樣:
$doc="<78>Nov 3 11:20:01 163.17.44.1 crond[30367]"; my $leftlist="a-zA-Z"; $_=$doc; # 用 $_ 設定預設的取代字串 eval "tr/$leftlist/ /, 1" or die $@; #把a-zA-Z換成空白 print $_."\n" ;
結果
<78> 3 11:20:01 163.17.44.1 [30367]
綜上所述,PERL的字元取代非常的好用,相信你會喜歡。
上一篇 15-進階比對 #2--使用更多修飾子
回到目錄 01-撰寫第一隻PERL程式
下一篇 17-參照