Learning Perl 學(xué)習(xí)筆記 Ch9 正則表達式(三)用正則表達式處理文本

  1. 重新理解正則表達式甥温,Perl中的正則表達式其實不是獨立的功能,只是內(nèi)嵌于某些功能中的子語言, m//就像是文本編輯器中的搜索功能济丘,Perl同樣提供了替換功能:s/正則表達式的模式/替換的內(nèi)容/惭载,如果沒有用=~綁定對象敢订,則默認替換的是預(yù)置變量$_
    demo9-1:
#!/usr/bin/perl
$_="This is a test.\n";
if($result = s/is/was/){
  print $_;
}
print "result:$result";

作為表達式,s///返回匹配結(jié)果的布爾值:

./demo9-1
Thwas is a test.
result:1

  • s///默認只會替換第一個匹配的位置厅缺,如果要實現(xiàn)全部替換蔬顾,需要修飾符/g
    demo9-2:
#!/usr/bin/perl
$_="This is a test.\n";
s/is/was/g;
print $_;
 ./demo9-2
Thwas was a test.

m//中的修飾符在s///中同樣可以使用宴偿,包括:
/i:忽略大小寫
/s:讓.匹配包括換行符在內(nèi)的任意字符
/x:允許在模式中插入任意空白和換行


  • m//一樣,在s///中也可以使用捕獲變量
    demo9-3:
#!/usr/bin/perl
$_="This is a test.\n";
s/(\w+) (\w+) (\w+) (\w+)/$4 $3 $2 $1/;
print $_;

把捕獲的變量逆序輸出

./demo9-3
test a is This.

我們也可以把反向引用加進去:
demo9-4:

#!/usr/bin/perl
$_="This is a test.\n";
s/(is) \1/were/;
print $_;

匹配到is is

 ./demo9-4
Thwere a test.

命名捕獲變量和自動捕獲變量同樣可以使用:
demo9-5:

#!/usr/bin/perl
$_="This is a test.\n";
s/(?<be>is)/_$+{be}_/;
print $`."\n";
print $&."\n";
print $'."\n";
print $_;
./demo9-5
Th
is
 is a test.

Th_is_ is a test.

  • s///的定界符可以替換诀豁,如果是非成對定界符(比如#)只需要重復(fù)三次來分割圈引模式和圈引替換模式窄刘,但如果是成對定界符(比如{}[])就需要成對使用兩次來區(qū)分圈引模式和圈引替換模式:
    s#abc#def#
    s{abc}[def]
    雖然 #也被用來表示注釋, 但如果Perl解析器在期待一個定界符,就不會把 #視作注釋的開頭)

  • s///的圈引替換模式中舷胜,有一組特殊的轉(zhuǎn)義字符可以實現(xiàn)大小寫轉(zhuǎn)換:
    \U:之后的字符全部轉(zhuǎn)換成大寫
    \L:之后的字符全部轉(zhuǎn)換為小寫
    \E:結(jié)束\U\L的作用范圍
    \u:之后的第一個字符大寫
    \l:之后的第一個字符小寫
    可以將\u\L或者\l\U連用實現(xiàn)首字母大寫或首字母小寫的功能:
    demo9-6
#!/usr/bin/perl
$_="This is a test.\n";
print $_;
s/(?<be>test)/\u\L$+{be}/;
print $_;
./demo9-6
This is a test.
This is a Test.

大小寫轉(zhuǎn)義字符的規(guī)則并不是s///專屬的娩践,任何雙引號內(nèi)的字符串都適用此規(guī)則
demo9-7

#!/usr/bin/perl
$_="This is a \u\Ltest.\n";
print $_;
s/(?<be>test)/\l\Utest/i;
print $_;
./demo9-7
This is a Test.
This is a tEST.


  1. 另一個使用正則表達式的是@result = split //,$string,操作符split會根據(jù)分隔符(寫成模式)將一個字符串截斷成子字符串列表。
    demo9-8:
#!/usr/bin/perl
$input = "Zhao:Qian:Sun:LI:Zhou:Wu:Zheng:Wang";
foreach (split /:/, $input){
  print $_."\n";
}

分隔符自己不會出現(xiàn)在列表中

./demo9-8
Zhao
Qian
Sun
LI
Zhou
Wu
Zheng
Wang

  • 如果字符串中兩個分隔符連著就會產(chǎn)生空字段烹骨,但是Perl會忽略末尾的空字段:
    demo9-9:
#!/usr/bin/perl
$input = "::Zhao::Qian::Sun::LI::Zhou::Wu::Zheng::Wang::";
foreach (split /:/, $input){
  print $_."\n";
}

在原來的每個字段之間和前后都加了額外的分隔符翻伺,但是結(jié)尾的空字段被舍棄了

./demo9-9


Zhao

Qian

Sun

LI

Zhou

Wu

Zheng

Wang

  • split的默認行為是用空白\s+分割存放于$_內(nèi)的字符串:
    demo9-10:
#!/usr/bin/perl
$_ = " Zhao Qian Sun LI Zhou Wu Zheng Wang ";
foreach (split){
  print $_."\n";
}

稍有不同之處在于所有空字段都被舍棄(因為連續(xù)的空白字符本身就匹配了\s+模式,所以不存在字符串內(nèi)部的空字段):

./demo9-10
Zhao
Qian
Sun
LI
Zhou
Wu
Zheng
Wang

標(biāo)準的寫法可能是 split /\s+/, $_;
demo9-11:

#!/usr/bin/perl
$_ = " Zhao Qian Sun LI Zhou Wu Zheng Wang ";
foreach (split /\s+/, $_){
  print $_."\n";
}

這樣則可以保留字符串前面的空字段沮焕,別忘了連續(xù)的空白字符本身就匹配了\s+模式穆趴,所以不存在字符串內(nèi)部的空字段

./demo9-11

Zhao
Qian
Sun
LI
Zhou
Wu
Zheng
Wang

  • split操作符功能相反的是join函數(shù)(沒錯,split是操作符遇汞,但是join是函數(shù))未妹,不過join并沒有使用模式:
    $result = join $glue, @pieces;
    join函數(shù)的功能是把@pieces中的字符串片段$glue膠水粘合成一個字符串$result, $glue保存著充當(dāng)膠水的字符串而不是模式
    join可以和split結(jié)合實現(xiàn)替換功能,效果類似s///g:
    demo9-12:
#!/usr/bin/perl
$_ = " Zhao Qian Sun LI Zhou Wu Zheng Wang ";
@pieces = split;
print join "&", @pieces;
print "\n";

&替換了空格

./demo9-12
Zhao&Qian&Sun&LI&Zhou&Wu&Zheng&Wang


  1. 列表上下文中使用m//會得到有趣的新特性:如果模式匹配成功空入,會返回所有捕獲變量的列表
    demo9-13:
#!/usr/bin/perl
$_ = "Zhang san   Li si  Wang wu  ";
@pieces = /([A-Z][a-z]+)/g;
foreach (@pieces){
  print $_."\n";
}

捕獲了([A-Z][a-z]+)首字母大寫其余字母小寫的單詞:

Zhang
Li
Wang

如果有多個捕獲模式就會返回多個捕獲串:
demo9-14:

#!/usr/bin/perl
$_ = "Zhang san   Li si  Wang wu  ";
@pieces = /([A-Z][a-z]+)\s+(\w+)/g;
foreach (@pieces){
  print $_."\n";
}

返回的列表里包含了所有捕獲串

./demo9-14
Zhang
san
Li
si
Wang
wu

特別地络它,如果捕獲的模式恰好是兩個,則可以用哈希結(jié)構(gòu)存儲m//返回的結(jié)果歪赢,這種情況下化戳,第一個捕獲的變量是哈希的鍵,第二個捕獲的是哈希的值:
demo9-15:

#!/usr/bin/perl
$input = "Zhang san   Li si  Wang wu  ";
%hash = ($input =~ /([A-Z][a-z]+)\s+(\w+)/g);
foreach (keys %hash){
  print $_."=>".$hash{$_}."\n";
}
./demo9-15
Wang=>wu
Li=>si
Zhang=>san


  1. 正則表達式中的量詞:*, +, ?, {M,N}默認都是貪婪量詞埋凯,即會盡可能多的匹配点楼,總會匹配到最大的字符串,而如果想要使用非貪婪量詞白对,只需要在原來的量詞后面加上?*?, +?, ??, {M,N}?掠廓,這種情況下會盡可能少的匹配:
    demo9-16:
#!/usr/bin/perl
$_ = "TAG a b c d ef ghi jk TAG lmn opq TAG rst uvw xyz TAG";
if(m/TAG (.+) TAG/){
     print "Greedy:".$&."\n";
}
if(m/TAG (.+?) TAG/){
     print "Non-greedy:".$&."\n";
}
 ./demo9-16
Greedy:TAG a b c d ef ghi jk TAG lmn opq TAG rst uvw xyz TAG
Non-greedy:TAG a b c d ef ghi jk TAG

  1. 使用鉆石操作符的新特性,結(jié)合正則表達式甩恼,使用Perl來修改文件:
    當(dāng)$^I變量中是字符串時蟀瞧,將賦予鉆石操作符<>新的特性:首先將@ARGV中字符串對應(yīng)的文件改名,加上后綴条摸,后綴內(nèi)容即是$^I內(nèi)存儲的值悦污,修改輸入指向這個文件,然后打開一個新文件钉蒲,命名為原來的文件名切端,修改輸出到這個新文件。
    demo9-17:
#!/usr/bin/perl -w 
use strict;
$^I=".bak";
chomp(my $date = `date`);
while(<>){
    s/Date:.*/Date:$date/;
    print;
}

另外創(chuàng)建一個文件寫上“Date:”, 則每次運行程序顷啼,都會把Date后的時間更新為當(dāng)前時間

echo "Date: " > test
./demo9-17 test

這時目錄下生成一個test.bak文件踏枣,存儲著修改前的內(nèi)容小压。 while循環(huán)里每次都會從test.bak里讀取一行放到$_里,然后用s///修改后椰于,打印到test文件里(輸出已經(jīng)被<>重定向到新文件里了)
如果$^I為空怠益,則修改就會直接作用在源文件上


因為這個程序太普遍,所以有了它的簡化版本:
perl -p -i.bak -w -e 'chomp(my $date=`date`);' -e 's/Date:.*/Date:$date/' tes*
可以直接在命令行執(zhí)行瘾婿,作用和 demo9-17相同
-p選項讓perl自動生成一段類似下面這樣的小程序:

while(<>){
print;
}

-e后面跟著程序代碼蜻牢,會插入到while循環(huán)之中
-i.bak$^I=".bak"的作用相同,如果只有-i那就像是把$^I變量置為空偏陪,則不會有備份動作發(fā)生抢呆。
最后一個參數(shù)表示設(shè)定@ARGV的值,這里使用了通配符

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末笛谦,一起剝皮案震驚了整個濱河市抱虐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌饥脑,老刑警劉巖恳邀,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異灶轰,居然都是意外死亡谣沸,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進店門笋颤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來乳附,“玉大人,你說我怎么就攤上這事伴澄「吵” “怎么了?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵非凌,是天一觀的道長举农。 經(jīng)常有香客問我,道長清焕,這世上最難降的妖魔是什么并蝗? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮秸妥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘沃粗。我一直安慰自己粥惧,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布最盅。 她就那樣靜靜地躺著突雪,像睡著了一般起惕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上咏删,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天惹想,我揣著相機與錄音,去河邊找鬼督函。 笑死嘀粱,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的辰狡。 我是一名探鬼主播锋叨,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼宛篇!你這毒婦竟也來了娃磺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤叫倍,失蹤者是張志新(化名)和其女友劉穎偷卧,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吆倦,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡涯冠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了逼庞。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蛇更。...
    茶點故事閱讀 38,814評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖赛糟,靈堂內(nèi)的尸體忽然破棺而出派任,到底是詐尸還是另有隱情,我是刑警寧澤璧南,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布掌逛,位于F島的核電站,受9級特大地震影響司倚,放射性物質(zhì)發(fā)生泄漏豆混。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一动知、第九天 我趴在偏房一處隱蔽的房頂上張望皿伺。 院中可真熱鬧,春花似錦盒粮、人聲如沸鸵鸥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽妒穴。三九已至宋税,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間讼油,已是汗流浹背杰赛。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留矮台,地道東北人乏屯。 一個月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像嘿架,于是被迫代替她去往敵國和親瓶珊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,728評論 2 351

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