學(xué)習(xí)筆記 Perl grep函數(shù)使用揭秘
本文和大家重點(diǎn)討論一下Perl grep函數(shù)的使用,Perl grep函數(shù)會(huì)根據(jù)LIST中的元素對(duì)BLOCK或EXPR做出評(píng)估,BLOCK塊是一個(gè)或多個(gè)由花括號(hào)分隔開的Perl語(yǔ)句。而List則是一串被排序的值。
Perl grep函數(shù)的使用
關(guān)于Perl grep函數(shù)
(如果你是個(gè)Perl的新手,你可以先跳過下面的兩段,直接到Grepvs.loops樣例這一部分,放心,在后面你還會(huì)遇到它)
grepBLOCKLIST
grepEXPR,LIST
Perl grep函數(shù)會(huì)根據(jù)LIST中的元素對(duì)BLOCK或EXPR做出評(píng)估,而且會(huì)把局部變量$_設(shè)置為當(dāng)前所用的LIST中的元素。BLOCK塊是一個(gè)或多個(gè)由花括號(hào)分隔開的Perl語(yǔ)句。而List則是一串被排序的值。EXPR是一個(gè)或多個(gè)變量,操作符,字符,函數(shù),子程序調(diào)用的綜合體。Grep會(huì)返回一組經(jīng)BLOCK或EXPR塊的估值后是真的元素。如果BLOCK塊由多個(gè)語(yǔ)句組成,那么Grep以BLOCK中的最后一條語(yǔ)句的估計(jì)值為準(zhǔn)。LIST可以是一個(gè)列表也可以是一個(gè)數(shù)組。在標(biāo)量上下文中,grep返回的是可以被BLOCK或EXPR估為真的元素個(gè)數(shù)。
請(qǐng)避免在BLOCK或EXPR塊中修改$_,因?yàn)檫@會(huì)相應(yīng)的修改LIST中的元素。同時(shí)還要避免把grep返回的列表做為左值使用,因?yàn)檫@也會(huì)修改LIST中的元素。(所謂左值變量就是一個(gè)在賦值表達(dá)式左邊的變量)。一些Perlhackers可能會(huì)利用這個(gè)所謂的"特性",但是我建議你不要使用這種混亂的編程風(fēng)格.
Perl grep函數(shù)與循環(huán)
這個(gè)例子打印出myfile這個(gè)文件中含有terriosm和nuclear的行(大小寫不敏感).
- openFILE"<myfile"ordie"Can'topenmyfile:$!";
 - printgrep/terrorism|nuclear/i,<FILE>;
 
對(duì)于文件很大的情況,這段代碼耗費(fèi)很多內(nèi)存。因?yàn)間rep把它的第二個(gè)參數(shù)作為一個(gè)列表上下文看待,所以<>操作符返回的是整個(gè)的文件。更有效的代碼應(yīng)該這樣寫:
- while($line=<FILE>){
 - if($line=~/terrorism|nuclear/i){print$line}
 - }
 
通過上面可以看到,使用循環(huán)可以完成所有g(shù)rep可以完成的工作。那為什么我們還要使用grep呢?一個(gè)直觀的答案是grep的風(fēng)格更像Perl,而loops(循環(huán))則是C的風(fēng)格。一個(gè)更好的答案是,首先,grep很直觀的告訴讀者正在進(jìn)行的操作是從一串值中選出想要的。其次,grep比循環(huán)簡(jiǎn)潔。(用軟件工程的說法就是grep比循環(huán)更具有內(nèi)聚力)?;旧?,如果你對(duì)Perl不是很熟悉,隨便你使用循環(huán)。否則,你應(yīng)該多使用像grep這樣的強(qiáng)大工具.
計(jì)算數(shù)組中匹配給定模式的元素個(gè)數(shù)
在一個(gè)標(biāo)量上下文中,grep返回的是匹配的元素個(gè)數(shù).
$num_apple=grep/^apple$/i,@fruits;^和$匹配符的聯(lián)合使用指定了只匹配那些以apple開頭且同時(shí)以apple結(jié)尾的元素。這里grep匹配apple但是pineapple就不匹配。
輸出列表中的不同元素
- @unique=grep{++$count{$_}<2}
 - qw(abacddefgfhh);
 - print"@unique\n";
 
輸出結(jié)果:abcdefgh$count{$_}是Perl散列中的一個(gè)元素,是一個(gè)鍵值對(duì)(Perl中的散列和計(jì)算機(jī)科學(xué)中的哈希表有關(guān)系,但不完全相同)這里count散列的鍵就是輸入列表中的各個(gè)值,而各鍵對(duì)應(yīng)的值就是該鍵是否使BLOCK估值為真的次數(shù)。當(dāng)一個(gè)值第一次出現(xiàn)的時(shí)候BLOCK的值被估為真(因?yàn)樾∮?),當(dāng)該值再次出現(xiàn)的時(shí)候就會(huì)被估計(jì)為假(因?yàn)榈扔诨虼笥?)。
取出列表中出現(xiàn)兩次的值
- @crops=qw(wheatcornbarleyricecornsoybeanhay
 - alfalfaricehaybeetscornhay);
 - @duplicates=grep{$count{$_}==2}
 - grep{++$count{$_}>1}@crops;
 - print"@duplicates\n";
 
在grep的第一個(gè)列表元素被傳給BLOCK或EXPR塊前,第二個(gè)參數(shù)被當(dāng)作列表上下文看待。這意味著,第二個(gè)grep將在左邊的grep開始對(duì)BLOCK進(jìn)行估值之前完全讀入count散列。
列出當(dāng)前目錄中的文本文件
@files=grep{-fand-T}glob'*.*';
print"@files\n";
glob函數(shù)是獨(dú)立于操作系統(tǒng)的,它像Unix的shell一樣對(duì)文件的擴(kuò)展名進(jìn)行估計(jì)。單個(gè)的*表示匹配所以當(dāng)前目錄下不以.開頭的文件,.*表示匹配當(dāng)前目錄下以.開頭的所有文件.如果一個(gè)文件是文本文件-f和-T文件測(cè)試符則返回真。使用-fand-T進(jìn)行測(cè)試要比單用-T進(jìn)行測(cè)試有效,因?yàn)槿绻粋€(gè)文件沒有通過-f測(cè)試,那么-T測(cè)試就不會(huì)進(jìn)行,而-f測(cè)試比-T耗時(shí)更少.
從數(shù)組中選出元素并消除重復(fù)
- @array=qw(Tobeornottobethatisthequestion);
 - print"@array\n";
 - @found_words=
 - grep{$_=~/b|o/iand++$counts{$_}<2;}@array;
 - print"@found_words\n";
 
輸出結(jié)果:
Tobeornottobethatisthequestion
Tobeornottoquestio
邏輯表達(dá)式$_=~/b|o/i匹配包含有b或o的元素(區(qū)別大小寫)。把匹配操作放在計(jì)數(shù)工作前要比把計(jì)數(shù)工作放在前面有效些。比如,如果左邊的表達(dá)式測(cè)試失敗,那么右邊的表達(dá)式就不會(huì)被計(jì)算.
選出二維坐標(biāo)數(shù)組中橫坐標(biāo)大于縱坐標(biāo)的元素
- #Anarrayofreferencestoanonymousarrays
 - @data_points=([5,12],[20,-3],
 - [2,2],[13,20]);
 - @y_gt_x=grep{$_->[0]<$_->[1]}@data_points;
 - foreach$xy(@y_gt_x){print"$xy->[0],$xy->[1]\n"}
 
輸出結(jié)果:
5,12
13,20
在數(shù)據(jù)庫(kù)中查找餐館
這個(gè)例子實(shí)現(xiàn)數(shù)據(jù)庫(kù)的方法不適合在實(shí)際中使用的,但是它說明了使用Perl grep函數(shù)的時(shí)候,只要你的內(nèi)存夠用,BLOCK塊的復(fù)雜度基本沒有限制.
- #@databaseisarrayofreferencestoanonymoushashes
 - @database=(
 - {name=>"WildGinger",
 - city=>"Seattle",
 - cuisine=>"AsianThaiChineseKoreanJapanese",
 - expense=>4,
 - music=>"\0",
 - meals=>"lunchdinner",
 - view=>"\0",
 - smoking=>"\0",
 - parking=>"validated",
 - rating=>4,
 - payment=>"MCVISAAMEX",
 - },
 - #{...},etc.
 - );
 - subfindRestaurants{
 - my($database,$query)=@_;
 - returngrep{
 - $query->{city}?
 - lc($query->{city})eqlc($_->{city}):1
 - and$query->{cuisine}?
 - $_->{cuisine}=~/$query->{cuisine}/i:1
 - and$query->{min_expense}?
 - $_->{expense}>=$query->{min_expense}:1
 - and$query->{max_expense}?
 - $_->{expense}<=$query->{max_expense}:1
 - and$query->{music}?$_->{music}:1
 - and$query->{music_type}?
 - $_->{music}=~/$query->{music_type}/i:1
 - and$query->{meals}?
 - $_->{meals}=~/$query->{meals}/i:1
 - and$query->{view}?$_->{view}:1
 - and$query->{smoking}?$_->{smoking}:1
 - and$query->{parking}?$_->{parking}:1
 - and$query->{min_rating}?
 - $_->{rating}>=$query->{min_rating}:1
 - and$query->{max_rating}?
 - $_->{rating}<=$query->{max_rating}:1
 - and$query->{payment}?
 - $_->{payment}=~/$query->{payment}/i:1
 - }@$database;
 - }
 - %query=(city=>'Seattle',cuisine=>'Asian|Thai');
 - @restaurants=findRestaurants(\@database,\%query);
 - print"$restaurants[0]->{name}\n";
 
輸出結(jié)果:WildGinger
【編輯推薦】
- Eclipse平臺(tái)中Perl腳本開發(fā)
 - Perl學(xué)習(xí)筆記----Perl命令行
 - Perl數(shù)組和引用使用指導(dǎo)
 - Perl基礎(chǔ) 解析Perl標(biāo)量和數(shù)組概念
 - Perl模式匹配中的特殊字符用法指南
 
 















 
 
 
 
 
 
 