學習Perl(4)

湖湘文化發表於2013-11-19
 

學習Perl4

雜湊
1)何謂雜湊
雜湊是一種資料結構,和陣列相同之處:可以包含任意多個值,並能讓你隨心所欲地取用這些值;和陣列不同之處:陣列是以數字來編索引,雜湊則是用名稱來找尋相應的值。
在雜湊裡,沒有固定的順序,也沒有所謂的第一個元素,它只是一些“鍵-值對”的組合。
雜湊的鍵全都是互不相同的任意字串,但是它們對應的值卻可能重複。
為什麼使用雜湊?:由名字找姓;由主機名稱找IP地址;由IP地址找主機名稱;由單詞找出單詞在檔案中出現的次數(常見的應用);由駕駛執照找出姓名等;
2)訪問雜湊元素
語法: $hash{$some_key} 這和陣列的做法類似,但是我們會在索引值(雜湊鍵)旁邊使用花括號,而不是方括號。另外,鍵表示式現在是字串,而不是數值:
$family_name{“fred”} = “filintstone”; $family_name{“barney”} = “rubble”;
當你對某個已存在的雜湊元素賦值,就會覆蓋先前的值;
訪問不在雜湊裡的值會得到undef

訪問整個雜湊:
若要引用整個雜湊,請以百分比符號(%)開頭,如%family_name
為了方便起見,雜湊可以被轉換成列表,反之亦然:
%some_hash = (“foo”,35,”bar”,12.4,2.5,”hello”,”Wilma”,1.72e30,”betty”,”byen”);
@any_array = %some_hash; #
“展開”雜湊,“鍵-值對”列表
雜湊的賦值運算:
雖然很少這樣做,但是雜湊可以用一般的賦值語法來複制:%new_hash = %old_hash;
比較常見的是以某種方式來轉換雜湊,比如可以建立一個反序的雜湊:
%inverse_hash = reverse %any_hash;
注意,只有在確定原先的值互不重複的情況下,才應該使用此技巧!
大箭號:
依照Perl的文法,在任何需要逗號的地方都可以使用大箭號(=>)來代替:
my %last_name = ( #雜湊可以是詞法變數
“fred” => “filintstone”,
“dino” => undef,
);

3
)雜湊函式
keysvalues函式:
keys函式會返回但前雜湊的所有的鍵,而values函式所返回的則是相應的每個值。假如雜湊裡沒有任何元素,則這兩個函式都會返回空列表:
#!/usr/bin/perl -w

my %hash = ("a" => 1,"b" => 2,"c" => 3);

my @k = keys %hash;

my @v =values %hash;

print "@k are:@kn";

print "@v are:@vn";
my $count = keys %hash;

print "The counts of keys are:$count.n";
Perl
不會維持雜湊中元素的順序,但是,無論鍵的順序如何,值的順序都和它一樣。
在標量上下文中,這兩個函式都會返回雜湊元素的個數,它們會迅速執行這項任務,而無需逐項計算雜湊中的每一個元素: my $count = keys %hash; #變成3,表示3組“鍵-值對”
each函式:
假如你想對整個雜湊進行迭代,使用each函式是常見的做法,它會返回含有兩個元素的列表,也就是“鍵-值對”。實際使用時,唯一合適用each函式的地方是在while迴圈中:
#!/usr/bin/perl -w

my %hash = ("a" => 1,"b" => 2,"c" => 3);

while ( ($key,$value) = each %hash ) {

print "$key => $valuen";

}
假如你需要依次處理雜湊,只要對鍵排序就可以了:
#!/usr/bin/perl -w

my %hash = ("a" => 1,"b" => 2,"c" => 3);

foreach $key (sort keys %hash) {

$value = $hash{$key};

print "$key => $valuen";

}

4)雜湊的典型用途
判斷某項雜湊元素的真假:
if ($books{$someone}) {

Print “$someone has at least one book checked out.n”;
}
exists
函式:
要檢視某個鍵是否存在於雜湊中,使用exists函式,假如雜湊中有這個鍵,它就會返回真值,無論相應的值是否為“真”:
if (exists $books{“dino”}) {

print “Hey,there’s a library card for dino!n”;
}

delete
函式:
delete函式將會從列表移除你所指定的鍵(和相應的值)。
my $person = "betty";

delete $books{$person}; #撤銷$person的借書證
雜湊元素的替換:
可以將單一雜湊元素替換到雙引號括住的字串內,但我們並不支援整個雜湊的替換。

習題:
1)寫一支程式,處理使用者所指定的名字並且彙報相應的姓:
#!/usr/bin/perl -w

my %last_name = ("fred" => "filntstone","barney" => "rubble","wilma" => "flintstone");

print "Choices of fred,barney,or wilman";

chomp(my $name = );

print "That's $name $last_name{$name}.n";
參考答案如下:
#!/usr/bin/perl -w

my %last_name = qw (

fred filntstone

barney rubble

wilma flintstone);

print "Enter a first name:fred,barney or wilma.n";

chomp(my $name = );

print "That's $name $last_name{$name}.n";
2
)寫一支程式,讀取一連串的單詞,一行一個,直到輸入結束,然後輸出一份列出每個單詞出現次數的列表:
#!/usr/bin/perl -w

print "Enter some words,each line for one word,then press Ctrl+Dn";

my(@words,%count,$word);

chomp(@words = );

foreach $word(@words) {

$count{$word} += 1;

}

foreach $word (keys %count) { #如果要排序,在keys前加上sort

print "$word was seen $count{$word} times.n";

}


正規表示式
1)何謂正規表示式
正規表示式在Perl裡通常稱為模式,是一個“匹配”或“不匹配”特定字串的模板。
另一個用到正規表示式的地方就是Unixgrep命令,它會檢查文字里哪幾行匹配你所指定的模式,然後輸出那幾行的內容。
不要把正規表示式與shell的“檔名匹配模式”(又稱為glob)弄混了。
2)使用簡易模式
要以某個模式(正規表示式)來匹配$_的內容,請將它放在兩個斜線(/)之間:
$_ = “yabba dabba doo”;
if (/abba/) {

print “It matched!n”;

}
由於模式匹配通常用來返回真或假值,所以往往會在ifwhile的條件表示式裡看到它。
所有能在雙引號內的字串中使用的“反斜線跳脫字元”也都可以在模式裡使用。
關於元字元:
點號(.)是萬用字元,它會匹配換行符(n)以外的所有單個字元,只能用來匹配一個字元。
反斜線也是元字元。
簡易的量詞:
星號(*)會匹配它的前一個專案0次或多次,如:/fredt*barney/
把星號想成“前面的東西可以重複出現任意多次,也可以是零次”可能會比較容易理解。
.*會匹配任意字元無限多次,“隨便什麼東西”模式,它匹配的是字串中的隨便什麼東西
星號的正式名稱是量詞,意思是它指定了前一個專案的數量。
加號(+)也是量詞,它會匹配前一個專案一次以上,如: /fred+barney/
把加號想成“不管前面出現什麼,再接著隨便幾個相同的東西”或許會比較容易理解。
問號(?)也是量詞,表示前一個專案是可有可無(出現一次或不出現)的。
因為這三個量詞指定了前一個專案重複出現的次數,所以它們都必須接在某個東西之後。
模式組:
圓括號(或稱小括號)用來歸組,圓括號也是元字元。
模式/(fred)+/會匹配像fredfredfred這種字串。
擇一匹配:
豎線(|)在這裡使用時通常念為“或”,表示左邊匹配或郵編匹配。
模式/fred (and | or) barney/可用來匹配任何含有fred and barneyfred or barney的字串。

3
)字符集
字符集就是方括號(或稱中括號)裡一連串可能的字元。它只會匹配單一字元,但是該字元可以是字符集裡的任何一個。可以使用連字元(-)來指定某個範圍的字元,如[a-zA-Z]
當然,字符集只是完整模式的一部分,它在Perl裡永遠不會單獨出現。
#!/usr/bin/perl -w

$_ = "The HAL-9000 requires authorization to continue.";

if (/HAL-[0-9]+/) {

print "The string mentions some model of HAL computer.n";

}
在字符集開頭加上插入記號(^)可用來排除字符集,如[^def]匹配這3個字元外的任何字元。

字符集簡寫:
代表任意數字的字符集[0-9]可被簡寫成d;簡寫w就是所謂的“單詞”字元:[A-Za-z0-9_]
當然,w並不會匹配一個“單詞”,它只會匹配“單詞”裡的一個字元。雖然如此,要匹配完整的單詞時,只要使用加號修飾符就行了,如:/fred w+ barney/
s
簡寫擅長處理空白,它相當於[ftnr],即換頁、製表、換行、回車、空格共5中空白符。
比較常見的做法是使用s*來匹配任意數目的空白,或用s+來匹配一個以上的空白。
反義簡寫的排除:
以上3種簡寫的反義,只要使用它們的大寫形式-DWS就可以了,它們所匹配的就是相應的小寫形式所不匹配的字元。如/[dA-Fa-f]+/可以用來匹配十六進位制數字。
另外一個複合字符集是[dD],表示任何數字或非數字,也就是會匹配任何字元!這是匹配任意字元(包括換行符)的常見做法。
習題:
1)使用測試程式並測試一個模式,讓它匹配任何含有fred的字串。
#!/usr/bin/perl -w

while (<>) {

if(/fred/) {

print "It matched!n";

}

}
參考答案如下:
#!/usr/bin/perl -w

while (<>) {

if(/fred/) {

print;

}

}

2

#!/usr/bin/perl -w

while (<>) {

if(/[fF]red/) {

print;

}

}

3

#!/usr/bin/perl -w

while(<>) {

if(/./) {

print;

}

}

4

#!/usr/bin/perl -w

while(<>) {

if (/[A-Z][a-z]/) {

print;

}

}

5

#!/usr/bin/perl -w

while(<>) {

if (/(wilma).*(fred)/) {

print;

}

}
參考答案如下:
#!/usr/bin/perl -w

while (<>) {

if (/wilma/) {

if (/fred/) {

print;

}

}

}
或者:#!/usr/bin/perl -w

while (<>) {

if (/wilma.*fred|fred.*wilma/) { #這樣寫是因為wilmafred的順序不確定

print;

}

}


以正規表示式進行匹配
1)以m//進行匹配
/i來進行不區分大小寫的模式匹配:
#!/usr/bin/perl -w

print "Would you like to play a game?";

chomp($_ = );

if (/yes/i) {

print "In that case,I recommend that you go bowling.n";

}
/s來匹配任意字元:
#!/usr/bin/perl -w

$_ = "I saw Barneyndown at the bowling alleynwith frednlast night.n";

if (/Barney.*Fred/s) {

print "That string mentions Fred after Barney!n";

}

組合選項修飾符:
#!/usr/bin/perl -w

while (<>) {

if (/barney.*fred/si) {

print "That string mentions Fred after Barney!n";

}

}

繫結運算子=~
#!/usr/bin/perl -w

print "Do you like Perl?(yes/no)";

my $likes_perl = ( =~ /byesb/i);

if ($likes_perl) {

print "You said earlier that you like Perl,so ...n";

}

模式內的內插
#!/usr/bin/perl -w

my $what = "larry";

while (<>) {

if (/^($what)/) {

print "We saw $what in beginning of:$_";

}

}

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/21256317/viewspace-776992/,如需轉載,請註明出處,否則將追究法律責任。