久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Learning Perl

 weicat 2006-02-27



我的評(píng)價(jià):
本書是perl的經(jīng)典入門書籍,,介紹了perl中最基本的概念和語法,,是perl入門的好書,,我
向所有想了解或?qū)W習(xí)perl語言的朋友推薦本書。書中穿插有perl語法形成的歷史和原因,,
使你能充分感受到perl語言的文化,,這也是perl流行的原動(dòng)力。本書行文流暢,,各知識(shí)點(diǎn)
介紹到位,,令人很容易明白,達(dá)到入門點(diǎn)睛的效果,。但本書的作用也就是入門而已,,目的很
明確,它沒有深入到perl腳本語言的高級(jí)部份,。如果你想了解perl的高級(jí)功能或使用perl
來更好地完成你的日常工作,,還需進(jìn)一步學(xué)習(xí),《perl語言編程》應(yīng)該是你最好的選擇,。
第一章 簡介
第二章 標(biāo)量數(shù)據(jù)
什么是標(biāo)量數(shù)據(jù),?
標(biāo)量(scalar)是perl中最基本的元素。大多數(shù)標(biāo)量要么是一個(gè)數(shù)字,,要么是一個(gè)字符串,。
perl基本上把它們視為可相互替換的東西。
數(shù)字
所有數(shù)字的內(nèi)部格式都一樣
在內(nèi)部,,perl一律把整數(shù),,浮點(diǎn)數(shù)按雙精度浮點(diǎn)數(shù)進(jìn)行計(jì)算。perl內(nèi)部沒有整數(shù)值----程序中
的一個(gè)整數(shù)常量被當(dāng)作等值的浮點(diǎn)數(shù),。
直接量(literal)指的是在perl源代碼中表示值的方式,,
浮點(diǎn)直接量	1.33,233.5,,-3.9
整數(shù)據(jù)直接量	0,,89,-66,,61_383_883_897_363(一個(gè)大數(shù),,用下劃線以示清晰)
非十進(jìn)制整數(shù)直接量
八進(jìn)制直接量以0開頭
十六進(jìn)制直接量以0x開頭
二進(jìn)制以0b開頭
從5.6版本開始,perl允許在直接量中加下劃線以示清晰,。0x50_65_7c
數(shù)值操作符
加	+	2 + 3
減	-	3 - 2
乘	*	2 * 3
除	/	2/3
模	%	10%3
指數(shù)	**	2**3
字符串
單引號(hào)字符串直接量	在引號(hào)間除了單引號(hào)或反斜杠以外的任何字符(包括換行符,,如果該
字符串連續(xù)占幾行)在字符串中表示該字符本身。要想得到一個(gè)斜杠,,需要連續(xù)寫兩個(gè)斜杠,,
要得到一個(gè)單引號(hào),需要加一個(gè)斜杠,。
雙引號(hào)字符串直接量	在雙引號(hào)內(nèi)的反斜杠開始發(fā)揮它的作用,,可以用來指定特定的控制字
符,。可以在雙引號(hào)里面內(nèi)插變量,。
雙引號(hào)內(nèi)的轉(zhuǎn)義字符完整列表
\n	換行
\r	回車
\t	制表符
\f	換頁
\b	退格
\a	響鈴
\e	Esc(ascii的轉(zhuǎn)義字符)
\007	任意ASCII碼的八進(jìn)制值(這里007=響鈴)
\x7f	任意ASCII碼的十六進(jìn)制值(這里07f=刪除)
\cC	任意Ctrl鍵組合字符(這里是Ctrl-C)
\\	反斜杠
\"	雙引號(hào)
\l	下一個(gè)字母小寫
\L	所有后面的字母小寫,,直到\E
\u	下一個(gè)字母大寫
\U	所有后面的字母大寫,直到\E
\Q	添加反斜杠引用后面的非單詞字符,,直到\E
\E	結(jié)束\L,\U,\Q
字符串操作符
.	連接兩個(gè)字符串		"hello" . "world"   =   "helloworld"
x	串重復(fù)操作符	"yang" x 3="yangyangyang"    次數(shù)使用前截成一個(gè)整數(shù),。4.8=4,小
于1的拷貝次數(shù)會(huì)得到一個(gè)空串,。
數(shù)字與字符串的自動(dòng)轉(zhuǎn)換
依賴于作用在標(biāo)量值上的操作符,。如果是+則是數(shù)據(jù),如果是.則是字符串,。
"z".6*7="z42" ,"12"*"3"=36
perl的內(nèi)置警告
可以要求perl在發(fā)現(xiàn)你程序有異常時(shí)給你一個(gè)警告,。使用 -w 選項(xiàng)。
#!/usr/bin/perl -w
標(biāo)量變量
變量(variable)是一個(gè)容器的名字,,用以存放一個(gè)或多個(gè)值,,變量的名字在程序中保護(hù)不
變,但它所包含的值在執(zhí)行過程中一般要不停地改變,。在perl中用美元符號(hào)標(biāo)識(shí),。$a,$test。
選擇好的變量名
適當(dāng)加一些下劃線可讓變量更易讀,,更易理解,。
標(biāo)量賦值(assignment)
操作符用等號(hào),它的左邊是變量名,,右邊是值,。
二元賦值操作符
+=	-=	*=	.=	**= and so on
用print輸出
print "hello world\n";
print "the answer",6*6,".\n";
在字符串中替換標(biāo)量變量
$meal = "brontosaurus steak";
$barney = "fred ate a $meal";   另一種寫法  $barney = ‘fred ate a‘.$meal;
如果標(biāo)量變量從未被賦過值,就用一個(gè)空串替換,。
操作符優(yōu)先級(jí)和結(jié)合性
善用小括號(hào)
perlk中的操作符優(yōu)先級(jí)和結(jié)合性與C一樣
比較操作符
相等		==	eq
不相等		!=	ne
小于		<	lt
大于		>	gt
小于等于	<=	le
大于等于	>=	ge
if控制結(jié)構(gòu)
if () {
...;
} else {
...;
}
布爾值
perl中沒有單獨(dú)的的布爾數(shù)據(jù)類型,不過,,它使用幾條簡單的規(guī)則,。
1、特殊值undef是假,。
2,、0是假,所有其它的數(shù)字是真,。
3,、空串‘‘是假,所有其它的字符串一般是真,。
4,、一個(gè)例外,,因?yàn)閿?shù)字和字符是等價(jià)的,所以0的字符形式‘0‘,和它的數(shù)值形式有同樣的值:
假,。
! 是取反的意思,,可以在真值前加,結(jié)果就變成了假,。
取得用戶輸入
<STDIN>從鍵盤得到一個(gè)值,。一般以\n字符結(jié)束。所以可利用該字符做條件控制,。
chomp操作符
它作用于一個(gè)變量,,此變量必須存放一個(gè)字符串,如果這個(gè)字符串以換行符結(jié)尾,,chomp
就把它去掉,。
$text = "a line of text\n";
chomp ($text);	去掉換行符
chomp($text =<STDIN>);	最常用的方法,讀文本,,不帶換行符
chomp是一個(gè)函數(shù),,所有它有返回值,即去掉的字符個(gè)數(shù),。
使用chomp時(shí)可以帶或不帶小括號(hào),,這是perl的另一個(gè)基本規(guī)則,除非去掉括號(hào)會(huì)改變意
思,,否則括號(hào)總是可有可無的,。
while控制結(jié)構(gòu)
重復(fù)執(zhí)行一個(gè)代碼塊,只要條件為真,。
$count = 0;
while ($count < 10 ) {
$count +=1;
print "count is now $count\n";	得到從1到10的值,。
}
undef值
變量在第一次賦值之前有特別的undef值,代表什么也沒有,。當(dāng)把它作為字符串時(shí),,其功能
相當(dāng)于一個(gè)空串。當(dāng)把它作為數(shù)字時(shí),,其功能相當(dāng)于0,。perl程序員經(jīng)常這樣使用。
很多操作符在操作數(shù)超出范圍或沒有意義時(shí)會(huì)返回undef值,,這樣一般不是什么問題,,但如
果打開perl的警告,則會(huì)導(dǎo)至一個(gè)警告,。
defined函數(shù)
測(cè)試一個(gè)值是undef還是非空字符串,,可以使用這個(gè)函數(shù)。它對(duì)undef返回假,其它所有情
況則返回真:
$madon = <STDIN>;
if (defined($madon) {
print "the input was $madon";
} else {
print "no input available!\n";
}
如果你想生成自已的undef值,,可以用古怪的undef操作符
$madon = undef;		好像它從來沒有被動(dòng)過
第三章 列表和數(shù)組
在perl中,,如果“單數(shù)”是標(biāo)量,那么“復(fù)數(shù)”則由列表和數(shù)組來表示,。
列表(list)是一個(gè)有序的標(biāo)量集合,,數(shù)組(array)是一個(gè)包含列表的變量。精確地說,,列表是數(shù)
據(jù),,而數(shù)組是變量,可以有一個(gè)不在數(shù)組的列表,,但每個(gè)數(shù)組變量都包含一個(gè)列表,。數(shù)組和
列表可以放任意多的元素,最小的是沒有元素,,而最大的可以把所有內(nèi)存耗盡,。這符合perl
的“沒有不必要的限制”哲學(xué)。
訪問數(shù)組的元素
數(shù)組元素用連續(xù)的整數(shù)編號(hào),,從0開始,,然后按1遞增。
$fred[0] = "a";
$fred[1] = "b";
$fred[2] = "c";
如果下標(biāo)所指的元素超出了數(shù)組的區(qū)間,,那么相應(yīng)的值就是undef,。
特殊的數(shù)組索引
如果你試圖存儲(chǔ)一個(gè)超出數(shù)組區(qū)間的數(shù)組元素,這個(gè)數(shù)組就會(huì)自動(dòng)按需擴(kuò)展,,對(duì)它的長度沒
有限制,,只要有足夠的內(nèi)存供perl使用。
$rocks[0] = "a";
$rocks[1] = "b";
$rocks[2] = "c";
$rocks[10] = "end";   現(xiàn)在就有6個(gè)undef元素,。
訪問最后一個(gè)元素的索引是$#rocks,。
負(fù)的數(shù)組索引從數(shù)組尾部算起,-1代表最后個(gè)元素,。
列表直接量
列表直接量(list literal)是小括號(hào)中的一列由逗號(hào)分隔的值,。例如:
(1,2,,3,,4)   (“fred”,43.4)  ()  (1..100)  (0..$#rocks)
“..”是區(qū)間操作符,,能生成一個(gè)順序列表。如上例中的從1到100,。列表可包含表達(dá)式或
變量,。
qw快捷方式
qw表示“被括引的單詞”(quoted words)或“用空白括住”(quoted by whitespace),perl
按單引號(hào)字符串處理它們,所以你不能像在雙引號(hào)字符串中那樣在qw列表中用\n或$fred),。
qw /a b c d/    等同于   ("a","b","c","d")
qw !a b c d!    等同于   ("a","b","c","d")
qw {a b c d}    等同于   ("a","b","c","d")
定界符可以選擇任意的標(biāo)點(diǎn),。
列表賦值
($fred,$barney,$dino) = ("a","b","c")
($fred,$barney) = ($barney,$fred)     交換它們的值,比c等語言方便很多,。
如果變量的個(gè)數(shù)小于值的個(gè)數(shù),,則多余的值會(huì)被無聲地忽略。
如果變量的個(gè)數(shù)多于值的個(gè)數(shù),,則多的變量會(huì)得到undef值,。
at符號(hào)@可以一次指定整個(gè)數(shù)組。這樣@rocks代表“所有的rocks”,。@rocks = qw / a b c/;
@copy = @quarry      從一個(gè)數(shù)組拷貝一個(gè)列表到另一個(gè)數(shù)組
pop and push操作符
正真的perl程序員不使用索引訪問數(shù)組,,這樣發(fā)揮不了perl的強(qiáng)項(xiàng)。我們經(jīng)常把數(shù)組當(dāng)信
息棧用,??偸菑牧斜淼挠覀?cè)加入新值或刪除。
pop操作取出一個(gè)數(shù)組的最后一個(gè)元素
@array = 5..9;
$fred = pop(@array);	$fred得到9,,@array現(xiàn)在有(5,6,7,8)
$barney = pop(@array);	$barney得到8,,@array現(xiàn)在有(5,6,7)
如果數(shù)組是空的,pop就不管它,,因?yàn)闆]有元素可刪除,,只返回undef。
push操作與pop對(duì)應(yīng),,它順數(shù)組的最后添加一個(gè)元素或一個(gè)元素列表,。
push(@array,0);		@array現(xiàn)在有(5,6,7,0)
@others = qw /1 2 3/;
push @array,@others	@array現(xiàn)在有(5,6,7,0,1,2,3)
注意:push的第一個(gè)參數(shù)或pop的唯一參數(shù)必須是一個(gè)數(shù)組變量,進(jìn)棧和出棧對(duì)直接量列表
來說是沒有意義的。
shift and unshift 操作
類似于push and pop,,shift and unshift對(duì)數(shù)組的頭部進(jìn)行相應(yīng)的操作,。
在字符串中替換數(shù)組
與標(biāo)量一樣,數(shù)組的值也可以被替換到雙引號(hào)字符串中,。
print "quartz @rocks limestone\n";  打印所有巖石,,用空格分開。
注意:不要把電子郵件地址放到雙引號(hào)字符串中,。
foreach控制結(jié)構(gòu)
foreach循環(huán)遍歷列表中的所有值,,對(duì)每個(gè)值執(zhí)行一個(gè)迭代(執(zhí)行一次循環(huán)體)
foreach $rocks ( qw /a b c/) {
print "one rock is $rocks.\n";	打印a b c。
}
Perl最喜歡的缺省變量:$_
如果你在foreach循環(huán)的開始忽略了控制變量,,perl就會(huì)使用$_,。
foreach (1..10) {		缺省使用$_
print "I can count to $_!\n";
}
$_ = "a";
print;   缺省打印$_
reverse操作符
reverse 取一個(gè)列表的值,然后返回相反順序的列表,。記住它只返回反序列表,,并不影響它
的參數(shù),如果返回值不被賦給別的變量,它是不保存,。
sort操作符
sort取一個(gè)列表的值,,然后按照內(nèi)部字符序進(jìn)行排序。
標(biāo)量和列表上下文
一個(gè)給定的表達(dá)式在不同的地方,,可能會(huì)有不同的含義,。
5 + something 		something必須是個(gè)標(biāo)量
sort something 		something必須是個(gè)列表
在標(biāo)量上下文中使用列表生成表達(dá)式
提供標(biāo)量上下文的表達(dá)式:
$fred = something;
$fred[3] = something;
123 + something
something +654;
if (something) {...}
while (something) {...}
$fred[something] = something;
提供列表上下文的表達(dá)式:
@fred = something;
($fred,$barney) = something;
($fred) = something;
push @fred,something;
foreach $fred (something) {...}
sort something;
reverse something;
print something;
在列表上下文中使用標(biāo)量生成表達(dá)式
如果一個(gè)表達(dá)式在正常情況下不生成一個(gè)列表值,那么自然它就會(huì)生成標(biāo)量值,,即一個(gè)元素
列表:
@fred = 6*7 	得到一個(gè)單元素列表(42)
注意,,因?yàn)閡ndef是個(gè)村標(biāo)量值,所以給一個(gè)數(shù)組賦undef并不能清空數(shù)組,,清空的更好方
法是賦一個(gè)空列表(),。
強(qiáng)制使用標(biāo)量上下文
可以使用scalar假函數(shù),它告訴perl提供一個(gè)標(biāo)量上下文,。
@rocks = qw /a b c d/;
print "i have",@rocks,"rocks!\n";		錯(cuò),,打印了石頭的名字
print "i have",scalar @rocks,"rocks!\n";	正確,打印石頭的數(shù)量
列表上下文中的<STDIN>
chomp (@lines = <STDIN>);	讀入那些行,,不帶換行符
第四章 子例程
系統(tǒng)與用戶函數(shù)
perl的子例程可以讓我們?cè)谝粋€(gè)程序中重復(fù)利用一塊代碼,,子例程名字是在前面加一個(gè)可有
可無的&符號(hào),有一條規(guī)則規(guī)定什么時(shí)候可以省略,。
定義一個(gè)子例程
使用關(guān)鍵字sub和子例程名定義,。可以放在程序的任何位置,。
sub marine {
$n += 1;
print "hello ,sailor number $n!\n";
}
注意:n 為全局變量
調(diào)用子例程
$marine;	輸出hello,sailor number 1!
$marine;	輸出hello,sailor number 2!
返回值
每個(gè)子例程在運(yùn)行過程中,,計(jì)算值是它一系列動(dòng)作的一部份。在子例程中得到的最后一個(gè)計(jì)
算值自動(dòng)成為返回值,。因此注意在向子例程增加代碼時(shí)要確保最后一個(gè)表達(dá)式的結(jié)果是你希
望的返回值,。“最后一個(gè)表達(dá)式”是指真正的,、被最后計(jì)算的表達(dá)式,,而不是正文的最后一
行。
參數(shù)
參數(shù)列表在子例程運(yùn)行期間被自動(dòng)地賦給一個(gè)特別的數(shù)組變量@_,。子例程可以訪問這個(gè)變
量以確定參數(shù)個(gè)數(shù)和參數(shù)的值,。也就是說,第一個(gè)參數(shù)被存在@_[0],第二個(gè)被存在@_[1]中,,
其它依次類推,。@_變量是子例程的局部變量,如果@_中有一個(gè)全局變量,,它就會(huì)在子例程
調(diào)用前被保存起來,,而在子例程返回時(shí)恢復(fù)原值,。
子例程中的私有變量
my操作符生成被稱為詞法變量(lexical variable)的私有變量。
local操作符
local的真正功能是把給定的變量的一個(gè)拷貝保存在一個(gè)秘密的地方(棧),。這個(gè)值在保存后
不能被訪問、修改,、刪除,,讀出、檢查,、打印等,。在perl中沒有辦法以接近被保存的值。
接著local把該變量設(shè)為空值(對(duì)標(biāo)量是undef,,對(duì)數(shù)組是空表),,或設(shè)為任何賦給它的值。
當(dāng)perl從子例程中返回時(shí),,會(huì)自動(dòng)將變量恢復(fù)為原先的值,。從效果上來看,這個(gè)變量被暫
時(shí)借用了片刻,。
local 和 my 的區(qū)別
local是全局變量,,可以想成“save”(在子例中調(diào)用時(shí)),在所有新代碼中只用my,,my比
local快,。
可變長參數(shù)列表
在perl中,經(jīng)常傳遞給子例程任意長度的參數(shù)列表,。子例程可以查看@_數(shù)組,,從而輕松地
判斷參數(shù)的個(gè)數(shù)。但在實(shí)際的perl編程中,,這類檢查幾乎沒有用過,,最好是讓子例程適應(yīng)
參數(shù)。
一個(gè)允許任意參數(shù)的例程
$maximum = &max(3,5,10,4,6);
sub max {
my ($max_so_far) = shift @_;
foreach (@_) {
if ( $_ > $max_so_far) {
$max_so_far = $_;
}
}
$max_so_far;
}
這段代碼使用了被稱作“高水位線(high-water mark)的算法,。在一次洪水之后,,當(dāng)水最后
一次漲潮和退潮時(shí),高水位線顯示了曾經(jīng)達(dá)到的最高水位,。
空的參數(shù)列表
返回一個(gè)undef,。
詞法(my)變量的說明
my可以在任何塊中使用,而不僅僅在子例程中,。例如可以在if,while or foreach中,。
use strict pragma
perl是一種特別寬松的語言,但也許你想讓perl把規(guī)則加強(qiáng)一些,,這可以用user strict pragma
(編譯指示)來安排,。pragma中給編譯器的提示,,告訴它關(guān)代碼的一些信息,這里,,use strict
pragma是告訴perl編譯器,,它應(yīng)該在本塊或源文件的其余部份強(qiáng)制使用一些好的程序設(shè)計(jì)
規(guī)則。
return操作符
該操作符立即從子例程中返回一個(gè)值,。
省略與字符(&)
原則在除與內(nèi)置函數(shù)名一致,,其它子例程都可以省略與字符。
第五章 散列
什么是散列,?
散列(hash)是一個(gè)數(shù)據(jù)結(jié)構(gòu),,與數(shù)組相同的是它可以含有任意數(shù)目的值并隨意讀取它們。
但與數(shù)組中由數(shù)字對(duì)值進(jìn)行索引不同,,散列用名字(name)查找值,。也就是說,索引不再
是數(shù)字,,而是任意的惟一字符串,,稱之為鍵(key)。它是一桶數(shù)據(jù),,不存在第一項(xiàng),,它是一
團(tuán)糟的,隨意的,,沒有固定的順序,。鍵總是被轉(zhuǎn)成字符串,如用數(shù)值50/20做鍵,,它就會(huì)被
變成“2.5”,。
散列可以任意大小,從空散列直以填滿內(nèi)存,。
在perl中巨大的散列并不可怕,,從三個(gè)和三百萬個(gè)鍵值對(duì)中取出一個(gè)數(shù)的速度差不了多少。
為什么要用散列
你有一組數(shù)據(jù)與另外一組數(shù)據(jù)相關(guān),。
如
名		姓
主機(jī)名		ip地址
ip地址		主機(jī)名
單詞		單詞出現(xiàn)的次數(shù)
用戶名		用戶使用的硬盤塊數(shù)
駕照號(hào)碼	名字
如果你的任務(wù)描述中包含“找到重復(fù)項(xiàng)”,,“唯一的”,“交叉引用”,,或“查表”之類的詞語,,
那么散列就會(huì)在實(shí)現(xiàn)中很有用處。
散列元素訪問
使用如下語法:
$hash{$some_key}
$a{"home"} = "first";
$a("hotel"} = "second",;
當(dāng)你在一個(gè)已存在的散列中存入東西時(shí),,會(huì)覆蓋以前的值。
訪問散列之外的元素會(huì)得到undef:
$a = $b{"test"};	這里沒有test,,得到undef,。
作為一個(gè)整體的散列
要訪問整個(gè)散列,,就使用%號(hào)做前綴。
為方便起見,,可以將散列轉(zhuǎn)換為一個(gè)列表,,并轉(zhuǎn)換回來,給散列賦值是一個(gè)列表上下文,,這
個(gè)表由鍵-值對(duì)組成
%hash = ("aa",33,"bay",11,2.5,"hello","cc","bb\n");
展開散列(unwind),,把散列轉(zhuǎn)換回鍵-值對(duì)應(yīng)列表。次序亂了,,但鍵-值還是成對(duì)出現(xiàn)的。
@array = %hash
print "@array";
bay,11,2.5,hello,cc,bb(一個(gè)換行符),,aa,33
散列賦值
%new_hash = %old_hash			perl將%old_hash展開成一個(gè)鍵-值對(duì)列表,,并賦值給
%new_hash。
%inverse_hash = reverse %any_hash	生成逆散列,,鍵變值,,值變鍵。前提是原散列值要唯一,。
大箭頭
用大箭頭把散列中的鍵-值對(duì)組織起來,。
my %hash = (
"aa" => "test1",
"bb" => "test2",
"cc" => "test3",	最后額外的逗號(hào)是無害的
);
散列函數(shù)
keys函數(shù)得到一個(gè)散列中所有當(dāng)前鍵構(gòu)成的一個(gè)列表,values函數(shù)得到一個(gè)相應(yīng)的值,。
my %hash = ("a" => "test1,"b" => "test2","c" =>"test3");
my @k =	 keys %hash		得到"a","b","c",。
my @v = values %hash		得到"test1","test2","test3"。
在一人標(biāo)量上下文中,,這些函數(shù)給出散列的元素個(gè)數(shù),。
my $count = keys %hash		得到3,即有三個(gè)鍵-值對(duì),。
each函數(shù)
該函數(shù)可以遍歷一個(gè)完整的散列,。每次返回一個(gè)鍵-值對(duì)作為一個(gè)二元元素列表。最后返回
一個(gè)空列表,。
while ( ($key,$value) = each %hash ) {
print "$key => $value\n";
}
exists函數(shù)
查看某鍵是否在散列中,。存在就返回真,不存在就返回假,。
delete函數(shù)
從散列中刪除指定的鍵(和相應(yīng)的值),。如無此鍵,它的任務(wù)就結(jié)束,。此時(shí)沒有警告或出錯(cuò)
信息給出來,。
第六章 I/O基礎(chǔ)
從標(biāo)準(zhǔn)輸入進(jìn)行輸入
while (defined($line = <STDIN>)) {
print "I saw $line";
};
因?yàn)樾休斎氩僮鞣谀愕竭_(dá)文件末尾時(shí)會(huì)返回undef,所以可以用它方便地跳出循環(huán),。
從鉆石操作符進(jìn)行輸入
“<>”是一種特殊的行輸入操作符,,它可以是也可以不是來自鍵盤的輸入,。
while (defined($line = <>)) {
chomp($line);
print "It was $line that I saw!\n";
};
如果用a,b,c三個(gè)參數(shù)調(diào)用該程序,將打印三個(gè)文件的內(nèi)容,。使用鉆石操作符,,就好像輸入
文件被合并到一個(gè)大文件中。上面程序可用快捷方式寫成:
while (<>) {
chomp;
print "It was $_ that I saw!\n";
};
大多數(shù)linux標(biāo)準(zhǔn)工具中,,短橫-代表標(biāo)準(zhǔn)輸入流,。
通常在一個(gè)程序中只用一個(gè)鉆石操作符,當(dāng)初學(xué)者在程序中放第二個(gè)鉆石時(shí),,其實(shí)他們一般
是想用$_,。記住,鉆石操作符讀取輸入,,但輸入本身是在$_中,。
調(diào)用參數(shù)
鉆石操作符并不是直接從字面上讀取調(diào)用參數(shù),它實(shí)際上讀取@ARGV數(shù)組,。它被perl解
釋器預(yù)設(shè)為調(diào)用參數(shù)的列表,。在程序中可以對(duì)該數(shù)組進(jìn)行賦值等操作。
@ARGV = qw# a b c #;	強(qiáng)制讀取這三個(gè)文件
while (<>) {
chomp;
print "It was $_ that I saw!\n";
};
向標(biāo)準(zhǔn)輸出進(jìn)行輸出
print @array;		aabbcc
print "@array";		aa bb cc
print <>;		cat 的源代碼
print sort <>;		sort 的源代碼
用printf進(jìn)行格式化輸出,和c類似,。
數(shù)組與printf
可動(dòng)態(tài)形成格式字符串,。
my @items = qw ( a b c );
my $format = "the items are:\n".("%10s\n" x @items);	在標(biāo)量上下文中使用@items得到它的長
度
printf $format,@items		在列表上下文中使用@items得到它的內(nèi)容
上下文太重要了。要好好感受,。
第七章	正則表達(dá)式的概念
正則表達(dá)式(regular expression),,在perl中經(jīng)常被稱為模式(pattern),是與一個(gè)給定字符
串匹配或不匹配的模版,。
不要把正則表達(dá)式和被稱為glod的shell的文件名匹配模式混淆,。比如*.pm匹配以.pm結(jié)尾
的文件名。
使用簡單的模式
要比較一個(gè)模式和$_的內(nèi)容,,只需把模式放在一對(duì)斜杠之間,,如下:
$_ = "aabbkdkdk";
if ( /aabb/ ) {
print "it matched!\n";
};
關(guān)于元字符
在正則表達(dá)式中有一組具有特殊意義的字符,叫元字符,,如:.號(hào)匹配任意單個(gè)字符(但不
匹配換行符),,加反斜杠會(huì)使它不再特殊。一對(duì)反斜杠配置一個(gè)真正的反斜杠,。
簡單的數(shù)量符
在模式中重復(fù)一些東西,。*號(hào)匹配前面的條目0次或多次。如:/foo\t*test/匹配在foo和test
間任意數(shù)目的制表符,。
.*	匹配任意字符,、任意次數(shù)。
+	匹配前面的條目一次或多次。
,?	匹配前面的條目是可選的,,只能發(fā)生一次或0次(即沒有)。
模式中的分組
可以用()括號(hào)分組,,所以小括號(hào)也是元字符,。如:
/abc+/		匹配abccccccccccccccccc
/(abc)+/	匹配abcabcabcabcabc
/(abc)*/	匹配任意字符串,甚至是空串,。
選擇
豎線 | 表示要么是左側(cè)匹配,,要么是右側(cè)匹配。此時(shí)讀做“或”,。
/aa|bb|cc|/		匹配一個(gè)含有aa或bb或cc的字符串,。
/aa( |\t)+bb/		匹配aa和bb中間被空格、制表符或兩者的混合串分隔
/aa( +|\t+)bb/		匹配aa和bb中間必須全是空格,,或全是制表符
/aa(and|or)bb/		匹配aa and bb 和aa or bb
一個(gè)模式測(cè)試程序
下面這個(gè)程序有助于在一些字符串上測(cè)試一個(gè)模式,,看看它匹配了什么,在哪里匹配的,。
#!/usr/bin/perl
while (<>) {
chomp;
if (/your_pattern_goes_here/) {
print "Matched : |$`<$&>$‘|\n";
} else {
print "No match.\n";
}
};
第八章 正則表達(dá)式提高
字符類
字符類(character class)即在一對(duì)中括號(hào)中列出的所有字符,可以匹配類中的任何單個(gè)字符,。
例如:[abcdefg]可以匹配這七個(gè)字符中的任何一個(gè),。可用“-”指定一個(gè)范圍,。如[a-h],[1-9]
等,。[\001-\177]匹配任何7比特ASCII碼。中括號(hào)中的“^”號(hào)是取反的意思,,如[^abc]匹配
除abc外的任何單個(gè)字符,。
字符類快捷方式
有些字符類的使用特別頻繁,所以就有了快捷方式,。如:所有數(shù)字的字符類[0-9]可以縮寫成
\d,,[A-Za-z0-9_]縮寫成\w。\s匹配空白,,它和[\f\t\n\r ]等同,,即等同一個(gè)含五種空白字符的
字符類,它們是換頁符,,制表符,,換行符,回車符和空格字符自已,。\s只匹配類中的一個(gè)字
符,,所以一般用\s*匹配任意數(shù)量的空白(包括沒有空白),或用\s+匹配一個(gè)或多個(gè)空白字符,。
以上快捷方式的反置寫法是用大寫形式表示,,\D,\W,\S,。
/[\dA-Fa-f]/匹配十六進(jìn)制數(shù)字。
/[\d\D]/匹配任何數(shù)字或任何非數(shù)字,,也就是任何字符,,包括換行符?!?”匹配除換行符外的
所有字符,。
/[^\d\D]/表示什么都不匹配。
通用數(shù)量符
前面我們見過三個(gè)數(shù)量符*,+,?,。但如果這三個(gè)不能滿足你的需要,,也可以用大括號(hào){}中的一
對(duì)由逗號(hào)隔開的數(shù)字來指定重復(fù)的最少和最多次數(shù)。如/a{5,15}/匹配重復(fù)5次到15次的字
母a,。如果省略第二個(gè)數(shù)(但包含逗號(hào)),,那么匹配的次數(shù)就沒有上限。如/a{3,}/就匹配一行
中連續(xù)出現(xiàn)的3個(gè)或多個(gè)a,,它沒有上限,。如果連逗號(hào)也沒有了,那么給出的數(shù)字就是一個(gè)
準(zhǔn)確的數(shù)字,。如/a{3}/匹配3個(gè)a,。
*	等價(jià)  {0,}
+	等價(jià)  {1,}
?	等價(jià)  {0,1}
錨位符
錨位符(anchor)可以用來為模式指定字符串的特定位置?!癪”標(biāo)志字符串的開頭,,“$”標(biāo)
志字符串的結(jié)尾。如/^a/匹配處于字符頭的abc,,不能匹配dda,/b$/匹配處于字符尾的aab,,
不能匹配abc。
/^s*$/匹配一個(gè)空行
/^abc$/匹配abc,又匹配abc\n
單詞錨位符
\b可以匹配一個(gè)單詞的兩端,,可以用/\babc\b/來匹配單詞abc,。
可以用一個(gè)單詞錨位符,如,,/\bth/可以匹配this,these,但不匹配method,。/er\b/匹配
hander,woner,但不匹配gerenic,lery.
非單詞邊界錨位符是\B,,它匹配任何\b不匹配的地方,。如/\bsearch\B/會(huì)匹配searches,searching
and searched.但不能匹配search or researching。
記憶的小括號(hào)
()可以用來把模式的一些部份組合起來,,它還有第二個(gè)功能,,它們要求正則表達(dá)式引擎記住
與小括號(hào)中的模式匹配的那部份子串。
反向引用
反向引用(backreference)就是回頭引用在當(dāng)前模式處理過程中保存的記憶。用一個(gè)么斜杠
來構(gòu)成,,如\1包含第一個(gè)正則表達(dá)式記憶,。即被第一對(duì)小括號(hào)匹配的字符串部份。
反向引用被用來匹配與模式在前面匹配的字符串完全一樣的字符串,。所以/(.)\1/匹配任意單
個(gè)字符,,在記憶1中記住它,然后再與記憶1匹配,。換句話說,,它匹配任意字符,后跟同一
個(gè)字符,。這樣,,這個(gè)模式會(huì)匹配雙字母式的字符串。如bamm-bamm和betty,。它和/../不一
樣,,/../匹配任意字符,后跟任意字符,,它們兩個(gè)可以一樣,,也可以不一樣。
記憶變量
正則表達(dá)式記憶的內(nèi)容在模式匹配結(jié)束后仍可通過特殊變量$1得到,。
優(yōu)先級(jí)
分四個(gè)級(jí)別
1,、最上面的是小括號(hào)。
2,、是數(shù)量符,*,,+,,?,,{1,,2},{1,,},,{1}
3、是錨位符和序列,,^,,$,\b,,\B,。
4、是堅(jiān)線 | 。
優(yōu)先級(jí)例子
/^aaa|bbb$/可能不程序員的意思,,它只匹配字符串a(chǎn)aa的開頭或字符串bbb的未尾,。程序員
更可能想要的是
/^(aaa|bbb)$/,它匹配一行中沒有其它東西,,除了aaa或bbb以外,。
第九章 使用正則表達(dá)式
使用m//進(jìn)行匹配
一對(duì)斜杠實(shí)際上是m//(模式匹配)操作符的一個(gè)快捷方式。如我們?cè)趒w//中所中,,你可以選
擇任何定界符對(duì)把內(nèi)容括住,。如m<aaa>,m(aaa),m{aaa},m[aaa],m!aaa!等,。如果選擇了反斜
杠,,就可以省略m。
選項(xiàng)修飾符
用/i進(jìn)行不區(qū)分大小寫的匹配,。
用/s進(jìn)行任何字符的匹配,,包括換行符。它把模式中的每個(gè)點(diǎn)變成和字符類[\d\D]一樣,,匹
配任何字符,,包括換行符。
可組合使用修飾符/is,,順序并不重要,。
綁定操作符=~
my $some_other = "I dream of betty rubble";
if ($some_other =~ /\brub/) {
print "Aye,there‘s the rub.\n";
}
看起來像個(gè)賦值語句,但它不是的,。它是說“這個(gè)模式缺省時(shí)匹配$_中的東西---但現(xiàn)在讓它
匹配左側(cè)的字符串”,。如果沒有綁定操作符,表達(dá)式就缺省使用$_,。
匹配變量
可以用$1,$2,$3,$4引用正則表達(dá)式記憶的第一到第四個(gè)記憶,。匹配變量是正則表達(dá)式強(qiáng)大功
能的一個(gè)重要部份,它能讓我們?nèi)〕鲆粋€(gè)字符串的一部份,。
$_ = "hello there,neighbor";
if (/\s(w+),/) {			記住空格和逗號(hào)之間的單詞
print "the word was $1\n.";      $1 就是 there
}
匹配變量可以是空串,。
記憶的持久性
匹配變量一般保留到下一次模式匹配成功。也就是除非匹配成功,,否則你不應(yīng)該使用這些匹
配變量,。
自動(dòng)匹配變量
$&	實(shí)際與模式匹配的那部份字符串就保存在這里。
if ("hello there, neighbor" =~ /\s(w+),/) {
print "that actually matched ‘$&‘.\n";
}
整個(gè)匹配部份是" there,"(一個(gè)空格,there,,一個(gè)逗號(hào)),,$1中是there,而$&中是整個(gè)匹配部
份,。
匹配部份之前的東西被存在$`,,之后的東西被存在$‘,。也就是說,$`含有正則表達(dá)式引擎在
找到匹配之前需跳過的部份,,而$‘則含有模式?jīng)]有到達(dá)的字符串的剩余部份,。如果把這三個(gè)
字符串按順序連在一起,那么你總會(huì)得到原字符串,。第七章的模式測(cè)試程序就是使用了這三
個(gè)神秘代碼,。print "match:|$`<$&>$‘|\n"
使用自動(dòng)匹配變量的代價(jià)是,會(huì)使用其它正則表達(dá)式的運(yùn)行會(huì)變得慢一些,。所以很多perl
程序員都盡量避免使用這些自動(dòng)匹配變量,。相反,他們會(huì)采用一些方法,,例如,,如果你只需
要$&,那就在整個(gè)模式的周圍加一對(duì)括號(hào),,然后使用$1,。
用s///進(jìn)行查換并替換
$_ = "he‘s out bowling with barney tonight.";
s/barney/killer;	用killer替換barney,如果匹配失敗,,什么也不會(huì)發(fā)生,。
print "$_\n";
s///有一個(gè)返回值,替換成功,,則為真,,否則為假。
用/g進(jìn)行全局替換
s///只替換一處,,/g修飾符告訴s///進(jìn)行所有可能的無交迭替換,。
全局替換的一個(gè)相當(dāng)常見的使用是壓縮空白,把任意數(shù)量的空白變成一個(gè)空格,。
s/\s+/ /g;	壓縮空白
s/^\s+//;	把前面的空白刪除
s/\s+$//;	把結(jié)尾的空白刪除
s///也可用不同的定界符,,如#,!號(hào)等,,但如果使用成對(duì)的字符,因?yàn)樗凶笥抑?,所?必須用兩對(duì),,一結(jié)放模式,一對(duì)放替換串,,如s[aaa][bbb],s(aaa)(bbb),甚至也可以用s<aaa>(bbb)
這樣不成對(duì)的定界符,。
s///也和m//一樣,有/i,/s修飾符和=~綁定操作符,。
$file_name =~ s/^.*///s;	在$file_name中,,去掉所有unix風(fēng)格的路徑,。
大小寫轉(zhuǎn)換
\U	強(qiáng)制后面的字符都用大寫	s/(aaa|bbb)/\U$1/gi     AAA BBB
\L	強(qiáng)制后面的字符都用小寫	s/(aaa|BBB)/\L$1/gi	aaa bbb
用\E關(guān)閉,當(dāng)寫成小寫形式時(shí),,\u,\l就只影響下一個(gè)字符,。
\u\L或\L\u	代表首字符大寫,與順序無關(guān),。
split操作符
它把一個(gè)字符串按照分割子(separator)分開,。
@fields = split /:/,"abc:def::a:b";	得到("abc","def","","a","b")。
@fields = split /:/,":::a:b:c:::";	得到("","","","a","b","c"),,結(jié)尾空字段被丟棄,。
在空白處分割也是常見的,使用/\s+/模式,。
split的缺省行為是在空白處分割$_,。如
my @fields = split;	等同于split /\s+/, $_;
join函數(shù)
在某種意義上,join完成split的相反過程,。它把一組片斷粘合起來形成一個(gè)字符串,。
my $a = join ":",1,2,3,4,5;	則$a 是"1:2:3:4:5"
join可以和split配合使用,把一個(gè)字符串分割后用不同的定界符恢復(fù)它,。如可以把1,2,3 變
成 1-2-3.
第十章 更多的控制結(jié)構(gòu)
unless控制結(jié)構(gòu)
if是表達(dá)式為真時(shí)執(zhí)行,,如果希望表達(dá)式為假時(shí)執(zhí)行可用unless(除非)。表示除非表達(dá)式
為真,,否則運(yùn)行這個(gè)代碼,。它就像一個(gè)具有相反條件的if語句,也可以理解成一個(gè)獨(dú)立的
else子句,。
unless ($aa = ~/^[A-Z_]\w*$/i) {
print "the value of \$aa doesn‘t look like a perl identifier name.\n";
}
等同于
if ($aa =~ /^[A-Z_]\w*$/i) {
} else {
print "the value of \$aa doesn‘t look like a perl identifier name.\n";
}
等同于
if (!$aa =~ /^[A-Z_]\w*$/i) {
print "the value of \$aa doesn‘t look like a perl identifier name.\n";
}
以上語句都被編譯成相同的內(nèi)部字節(jié)碼,,但unless最自然。
unless的else子句
unless ($aa =~/^(bb)/) {
print "this value like bb.\n";
} else {
print "do you see what‘s going on here?\n";
}
等同于
if ($aa =~/^(bb)/) {
print  "do you see what‘s going on here?\n";
} else {
print "this value like bb.\n";
}
until控制結(jié)構(gòu)
while的反置結(jié)構(gòu),。
until ($a > $b) {
$a *= 2;
}
這個(gè)循環(huán)一直執(zhí)行,,直到條件表達(dá)式返回真為止。
表達(dá)式修飾符
print "$n is a negative number.\n" if $n < 0;
等同于
if ($n < 0) {
print "$n is a negative number.\n";
}
前一種寫法更緊湊,。讀起來很像自然英語,。還有:
print " ",($n +=2) while $n < 10;
$i *= 2 until $i >$j;
&greet($_) foreach @person;
裸塊控制塊
所謂的“裸(naked)塊”,指的是沒有關(guān)鍵字或條件的塊,。如:
while (condition) {
body;
body;
body;
}
現(xiàn)在把while關(guān)鍵字和條件去掉,,就得到一個(gè)裸塊。
{
body;
body;
body;
}
它只執(zhí)行一次,,然后就結(jié)束,,
其中一個(gè)作用是提供一個(gè)臨時(shí)詞法變量的作用域。一條通用的原則,,所有變量就應(yīng)該在最小
的作用域中聲明,。如果你需要一個(gè)只用在幾行代碼中的變量,,那么你可以把這些行放在裸塊
中,并在該塊中聲明這個(gè)變量,。
elsif子句
如果你需要檢查一組條件,,一個(gè)接一個(gè),看看哪個(gè)條件為真,,就可以用elsif子句(注意不
是elseif),。perl會(huì)逐個(gè)測(cè)試條件表達(dá)式,當(dāng)一個(gè)條件成功就執(zhí)行相應(yīng)的代碼,。但如果測(cè)試項(xiàng)
太多,,就不要使用這種方式,應(yīng)該用類“case or switch”的語句,。
自遞增和自遞減
++	$a++;	$a值不變,。
++$a;	把$a增1,存到$a里,。
--	$a--;	$a值不變,。
--$a;	把$a減1,存在$a里,。
for控制結(jié)構(gòu)
for ($i =1 ;$i <=10;$i++) {
print "I can count to $i!.\n";
}
for ($_ = "aaabbbccc";s/(.)//; ) {	當(dāng)s///成功時(shí)執(zhí)行循環(huán),。
print " one character is :$1\n."
}
每次迭代時(shí)都會(huì)去掉一個(gè)字母。當(dāng)字符串為空時(shí),,替換失敗,,循環(huán)結(jié)束。
以下用for實(shí)現(xiàn)的無限循環(huán)
for (;;) {
print "this is an infinite loop.\n";
}
以下為用while實(shí)現(xiàn)的無限循環(huán),,一種更具perl特色的寫法,。
while (1) {
print "this is an infinite loop.\n";
}
foreach和for之間的秘密聯(lián)系
在perl內(nèi)部,foreach 和 for 完全等價(jià),。
for (1..100) {				實(shí)現(xiàn)是一個(gè)從1到100的foreach循環(huán)
print "I can count to $_.\n";
}
在perl中,,foreach總是被寫成for,因?yàn)榭晒?jié)省4個(gè)字符的輸入,,因?yàn)閼卸枋莗erl程序中的
經(jīng)典品質(zhì),。
循環(huán)控制
last操作符	立即終止一個(gè)循環(huán)的執(zhí)行(與c中的break相似)。作用于當(dāng)前運(yùn)行的最內(nèi)層
循環(huán)塊,。
next操作符	控制從循環(huán)的下一個(gè)迭代繼續(xù)(與c中的continue相似)
redo操作符	回到當(dāng)前循環(huán)的開頭,,但不測(cè)試條件表達(dá)式,進(jìn)入下一次迭代,。
next 和 redo 最大的區(qū)別在于next會(huì)進(jìn)入到下一次迭代,而redo則重新執(zhí)行當(dāng)前的迭代,。
帶標(biāo)簽的塊
很少使用,,也就是命令一個(gè)循環(huán),,以便從內(nèi)層循環(huán)中直接跳出。
LINK: while (<>) {
foreach (split) {
last LINK if /__END__/;	跳出LINE循環(huán),。
...;
}
}
邏輯操作符
&&	相當(dāng)于and
||	相當(dāng)于or
它們被稱為短路操作符,。
三元操作符 ?
和c的一樣,它就像一個(gè)if-then-else測(cè)試,。
expression ? if_true_expr : if_false_expr
一個(gè)利用三元操作符寫的多路分支程序
my $size =
($width < 10) ? "small"   :
($width < 20) ? "medium"  :
($width < 50) ? "large"   :
"extra-large";    缺省值,。
使用部份計(jì)算操作符的控制結(jié)構(gòu)
&&,||,?:都有一個(gè)共有的屬性,依賴于左側(cè)值的真假,,它們可能計(jì)算可不計(jì)算一個(gè)表達(dá)式,,
因此叫部份計(jì)算
(partial-evaluation)操作符。因此它天生就是一種控制結(jié)構(gòu),。
第十章 文件句柄和文件測(cè)試
什么是文件句柄,?
文件句柄(filehandle)是Perl程序中的一個(gè)名字,表示你的Perl進(jìn)程與外面世界的i/o連接,。
它是一個(gè)連接的名字,,并不是一個(gè)文件的名字。
文件句柄的命名方式與其它perl標(biāo)識(shí)符一樣,,建議用大寫字母,。
Perl為了自已使用,已經(jīng)有六個(gè)特殊的文件句柄名:STDIN,STDOUT,STDERR,DATA,ARGV
AND ARGVOUT,。
打開一個(gè)文件句柄
open CONFIG,"test";		打開test文件,,它所包括的東西通過名為CONFIG的文件句柄
為我們的程序所使用。
open CONFIG,"<test";		打開test文件,,顯式說明這個(gè)文件名用于輸入,。
open CONFIG,">test";		打開test文件,顯式說明這個(gè)文件名用于輸出,。為了輸出打開文
件句柄CONFIG到新文件test,。
open CONFIG,">>logtest";	打開logtest文件,用于附加,。如果文件不存在則生成它,。
關(guān)閉一個(gè)文件句柄
close CONFIG;
退出程序時(shí)文件句柄會(huì)自動(dòng)關(guān)閉,但建議最好在完成一個(gè)文件句柄的使用后不久就關(guān)閉它,。
壞文件句柄
系統(tǒng)中會(huì)存在壞文件句柄,,如果你試圖向一個(gè)壞文件句柄寫入,那么數(shù)據(jù)會(huì)被無聲地丟棄,。
在編寫腳本時(shí)用perl -w會(huì)打開警告顯示,。
用die表明致命錯(cuò)誤
unless (open LOG,">>logtest") {
die "Cannot create logtest:$!";
}
或者用另外一種更好的寫法
open LOG, ">>logtest" or die "Cannot create logtest:$!";	使用or操作符。如果open成功,,返
回真,,or結(jié)束,,如果open失敗,返回假,,or會(huì)繼進(jìn)行到右側(cè)代碼,。伴隨一條消息死去。你
可以用語言去讀它,,“打開這個(gè)文件,,或死去”。
$!是系統(tǒng)給出的出錯(cuò)提示信息,,如果die表明的錯(cuò)誤并非來自一個(gè)系統(tǒng)請(qǐng)示失敗,,請(qǐng)不要包
含$!。
die "Not enouht arguments.\n" if @ARGV < 2;	命令參數(shù)不夠兩個(gè)時(shí),,程序退出,。
使用warn發(fā)出警告信息
與die類似,但它不退出程序,。
使用文件句柄
一旦打開一個(gè)文件句柄,,你就可以讀入行。像使用STDIN從標(biāo)準(zhǔn)輸入讀取一樣,。例如從unix
的passwd文件中讀取行:
open PASSWD, "/etc/passwd"
or die ”How did yo get loged in?($!)";
一個(gè)為寫入或附加打開的文件句柄可以和print or printf一起使用,,緊跟在其后但在參數(shù)列表
之前:
print LOG "filehandle test.\n"		輸出到LOG
改變?nèi)笔〉妮敵鑫募浔?缺省情況下,如果沒有給print指定一個(gè)文件句柄,,輸出就會(huì)發(fā)送到STDOUT,,但這個(gè)行為
可以用select操作符改變。
select LOG;
print "this message send to LOG.\n";
一旦選擇一個(gè)文件句柄作為缺省的輸出,,它會(huì)一直保留,,這樣會(huì)把后面的程序搞糊涂,所以
要在完成后及時(shí)設(shè)回STDOUT,。
select STDOUT;
重新打開一個(gè)標(biāo)準(zhǔn)文件句柄
如果三個(gè)系統(tǒng)句柄(STDIN,STDOUT,STDERR)的任何一個(gè)不能打開,,Perl會(huì)友好地恢復(fù)原來
的那個(gè),也就是說perl只有在看到新的連接打開成功時(shí)幫把原來的關(guān)掉,。
文件測(cè)試
在perl中有一組完整的測(cè)試,,你可以用來了解文件的信息。
-e 測(cè)試文件是否存在
die "ooo!my gods,a file called "$file"already exists.\n" if -e $file;
-M 檢查一個(gè)文件是否最新
warn "config file is looking pretty old!\n"
if -M CONFIG > 28;
文件測(cè)試和它們的含義
-r	文件或目錄對(duì)該(有效)用戶或組可讀
-w	文件或目錄對(duì)該(有效)用戶或組可寫
-x	文件或目錄對(duì)該(有效)用戶或組可執(zhí)行
-o	文件或目錄被該(有效)用戶或組所有
-R	文件或目錄對(duì)該實(shí)際用戶或組可讀
-W	文件或目錄對(duì)該實(shí)際用戶或組可寫
-X	文件或目錄對(duì)該實(shí)際用戶或組可執(zhí)行
-O	文件或目錄被該實(shí)際用戶或組所有
-e	文件或目錄名存在
-z	文件存在,,大小為零,,對(duì)目錄總為假
-s	文件或目錄存在,大小非零,,單位為字節(jié)
-f	條目是個(gè)普通文件
-d	條目的個(gè)目錄
-l	條目是個(gè)符號(hào)鏈接
-S	條目是個(gè)套接字
-p	條目是個(gè)命名管道(一個(gè)fifo)
-b	條目是個(gè)塊特殊(block-special)文件(如一個(gè)可裝載磁盤)
-c	條目是個(gè)字符特殊(character-special)文件(如一個(gè)i/o設(shè)備)
-u	文件或目錄是setuid
-g	文件或目錄是setgid
-k	文件或目錄的粘著位sticky bit被設(shè)置
-t	文件句柄是個(gè)TTY(可以由isatty()函數(shù)返回,,文件名不能由本測(cè)試來測(cè)試)
-T	文件像個(gè)“文本”文件
-B	文件像個(gè)“二進(jìn)制”文件
-M	更改年齡(單位為天)
-A	訪問年齡(單位為天)
-C	Inode更改年齡(單位為天)
stat和lstat函數(shù)
stat返回unix的stat系統(tǒng)調(diào)用返回的所有信息。它的操作數(shù)是一個(gè)文件句柄或是一個(gè)文件名。
返回值可能是一個(gè)空列表,,表示stat失?。ㄍǔJ俏募淮嬖冢蛘呤且粋€(gè)13個(gè)元素的數(shù)
字列表,。可用以下標(biāo)量變量列表描述出來,。
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) =
stat($filename);
$dev	文件設(shè)置號(hào)
$ino	文件inode號(hào)
$mode	文件權(quán)限位和一些特別位
$nlink	指向文件或目錄的鏈接數(shù)
$uid	文件的用戶id
$gid	文件的組id
$size	文件大?。ㄒ宰止?jié)為單位)
$atime	$mtime  $ctime  訪問,修改,,改變時(shí)間
$blksize	塊大小
$blocks	塊數(shù)
對(duì)符號(hào)鏈接使用stat將返回該鏈接所指的東西的信息,,而不是符號(hào)鏈接本身,除非這個(gè)鏈接
碰巧沒有指向任何目前可以訪問的東西,。如果你需要(基本上沒用)符號(hào)鏈接本身的信息,,
就使用lstat。如果操作數(shù)不是一個(gè)符號(hào)鏈接,,lstat則返回與stat一樣的東西,。
localtime函數(shù)
把電腦時(shí)間轉(zhuǎn)換成人可以看得明白的日期時(shí)間。
my $timestamp = 19809999393
my $date = localtime $timestamp
在列表上下文中,,localtime返回一個(gè)數(shù)字列表,。
my ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst) = localtime $timestamp
$mon	表示月份,從0-11,。
$year	表示自1900年起的年數(shù),,要加上1900才是真正的年數(shù)。
按位操作符
&	按位與----得到哪些位在兩個(gè)操作數(shù)中同時(shí)為真
|	按位或----得到哪些位在兩個(gè)操作數(shù)中至少有一個(gè)為真
^	按位異或----得到哪些位在兩個(gè)操作數(shù)中只有一上為真
<<	按位左移----把左操作數(shù)的位移動(dòng)由右操作數(shù)給定的次數(shù),,在低位補(bǔ)上0
>>	按位右移----把左操作數(shù)的位移動(dòng)由右操作數(shù)給定的次數(shù),,低位會(huì)被丟棄
~	按位取反,也被稱為一元位補(bǔ)----返回與操作數(shù)的每位相反的數(shù)
使用位串
如果一個(gè)按位操作符的任何操作數(shù)是一個(gè)字符串,,perl就會(huì)進(jìn)行位串操作,。也就是說"\xAA"
| "\x55" 會(huì)得到字符串"\xFF"。
使用特殊的下劃線文件句柄
_	特殊的文件句柄,,使perl用上次文件測(cè)試,、stat,lstat函數(shù)操作后留在內(nèi)存中的信息。
第十二章 目錄操作
改變目錄樹
chdir操作符可以改變工作目錄,,就像cd命令一樣,。
chdir "/etc" or dir "cannot cddir to /etc:$!";
glob
shell通常會(huì)把每個(gè)命令中的文件名模式擴(kuò)展為匹配的文件名,這就稱為glod,。 如ls *.txt
perl中的類似的glob操作符,。
my @all_files = glob "*";	得到當(dāng)前目錄中的所有文件,不包含以句點(diǎn)開頭的文件。
my @pm_files = glob ".pm";	得到以.pm結(jié)尾的文件,。
glob的另一種作法
在一些老程序中用<>代替glob操作符
my @all_files = <*>;
目錄句柄
目錄句柄(directory handle)和文件句柄在外表和操作上都很像,,可以打開它(用opendir),
讀取它(用readdir),關(guān)閉它(用closedir)。它讀出的是目錄的內(nèi)容,。
my $dir_to_process = "/etc";
opendir DH,$dir_to_process or die "cannot open $dir:$!";
foreach $file (readdir DH) {
print "one file in $dir is $file\n";
}
closedir DH;
與文件句柄類似,,目錄句柄會(huì)在程序結(jié)束時(shí)或該目錄句柄在其它目錄上重新打開時(shí)被自動(dòng)關(guān)
閉。
如果我們只想要那些以pm結(jié)尾的文件,,可以在循環(huán)中使用一個(gè)跳過函數(shù)
while ($name =readdir DIR) {
next unless $name =~ /\.pm$/;
.....
}
如果要非點(diǎn)文件可以用:next if $name =~ /^\./;
如果想要除. 和 ..之外的文件可用: next if $name eq "." or $name eq "..";
readdir操作符返回的文件沒有路徑名部份,,僅僅是目錄內(nèi)的文件名。如passwd,而不是
/etc/passwd
名字補(bǔ)丁,,加上路徑名,。
opendir SOMEDIR, $dirname or die "cannot open $dirname:$!";
while (my $name = readdir SOMEDIR) {
next if $name =~ /^\./;		跳過點(diǎn)文件
$name = "$dirname/$name";	補(bǔ)上路徑名
next unless -f $name and -r $name 	只要可讀文件
.....
}
遞歸的目錄列表
遞歸地訪問目錄可用File::Find庫。以進(jìn)行簡潔的遞歸目錄處理,。不用自已寫代碼,。
第十三章   處理文件和目錄
刪除文件
在perl中用unlink操作符刪除文件,同shell的rm命令一樣,。
unlink "aa","bb","cc";		把這三個(gè)文件刪除,。
與glob函數(shù)結(jié)合起來可以一次刪除多個(gè)文件
unlink glob "*.o";	刪除當(dāng)前目錄下以.o結(jié)尾的文件,與rm *.o相似,。
unlink的返回值告訴我們有多少文件被成功刪除,。
my $successful = unlink "aa","bb","cc";
print "I delete $successful   file(s) just now.\n";
如果想知道那個(gè)文件被刪除,可用循環(huán),,一次刪除一個(gè)文件,。
foreach my $file (qw/aa,bb,cc/) {
unlink $file or warn "failed on $file:$!";
}
一個(gè)很少人知道的有關(guān)unix的事實(shí)。如果你有一個(gè)文件,,你對(duì)它不能讀,,不能寫,不能執(zhí)
行,,甚至文件可能并不屬于你,,但你仍然可以刪除它。這是因?yàn)閡nlink一個(gè)文件的權(quán)限不
依賴于文件本身的權(quán)限位,,起作用的其實(shí)是包含這個(gè)文件的目錄的權(quán)限位,。只要目錄是可寫
的,就可以刪除該目錄中不屬于自已的文件,。在unix中可以通過設(shè)置sticky bit解這個(gè)問題,,
以保護(hù)可寫目錄。
重命名文件
rename "old","new";
類似于mv命令,。rename失敗時(shí)返回假,,并在$!中設(shè)置操作系統(tǒng)的錯(cuò)誤信息。因此可用or die
或or warn顯示給用戶。
一個(gè)把所有以.old結(jié)尾的東西rename為以.new結(jié)尾的perl程序,。
foreach my $file (glob "*.old") {
my $newfile = $file;
$newfile =~ s/\.old$/.new/;	由于.new不是模式,,所以點(diǎn)號(hào)不用加反斜杠。
if (-e $newfile) {
warn "can‘t rename $file to $newfile:$newfile exists.\n";
} elsif ( rename $file, $newfile) {
} else {
warn "rename $file to $newfile failed:$!\n";
}
}
鏈接和文件
每個(gè)文件都被存在一個(gè)編了號(hào)的inode中,,每個(gè)inode都包含一個(gè)稱為鏈接計(jì)數(shù)(link count)
的數(shù)字,,當(dāng)inode沒有列在任何目錄中時(shí),鏈接計(jì)數(shù)總是0,,也就是空,,可以分配給文件。
當(dāng)inode被加到一個(gè)目錄中時(shí),,鏈接計(jì)數(shù)會(huì)遞增;如果此列表項(xiàng)被刪除,,鏈接計(jì)數(shù)會(huì)遞減,。
目錄包含.,也就是指向自已的inode,,所以目錄的鏈接計(jì)數(shù)應(yīng)該總是至少為2,。文件也可以
不止一個(gè)列表項(xiàng),如鏈接文件,。在perl中用link "aa","bb"建立一個(gè)指向aa的鏈接bb,。類似
于在unix shell一執(zhí)行"ln aa bb"。現(xiàn)在aa,bb都有相同的inode值,,兩個(gè)文件有相同的大小,,
相同的內(nèi)容。在aa中加入一行,,也會(huì)在bb中加入一行,。如果意外刪除了aa,數(shù)據(jù)并不會(huì)丟
失,,可以在bb中找回來,。反之也一樣。但如果兩個(gè)文件都刪除了,,則數(shù)據(jù)就會(huì)丟失,。
目錄列表項(xiàng)中的鏈接規(guī)則
1、	一個(gè)給定的目錄列表項(xiàng)中的inode號(hào)都指向同一個(gè)安裝卷上的inode,。這條規(guī)則保證,,如
2、	果物理媒介被移到了另一臺(tái)機(jī)器上,,所有的目錄仍和它們的文件呆在一起,。這就是為什
3、	么可用rename把文件從一個(gè)目錄移到另一個(gè)目錄的原因,但兩個(gè)目錄必須在同一個(gè)文
4,、	件系統(tǒng)(安裝卷)中,。
鏈接不能用于目錄。
2,、不能給目錄起新的名字,。因此目錄不能用于鏈接。
以上討論的是硬鏈接,,還有一個(gè)符號(hào)鏈接,,也叫軟鏈接,能繞過這硬連接的限制,。
symlink "aa","bb";
or warn "cannot symlink aa to bb:$!";
這和unix shell 中的"ln -s aa bb" 類似,。
要想知道符號(hào)鏈接指向哪里,可以使用readlin函數(shù),。如果不是符號(hào)鏈接,,則返回undef。
兩種鏈接都要以用unlink刪除,。
建立和刪除目錄
mkdir函數(shù)可以在一個(gè)已有的目錄中建立一個(gè)目錄,。返回真時(shí)表示成功。
mkdir "aaa",0755 or warn "cannot make aaa directory:$!";
第二個(gè)參數(shù)是新生成目錄的權(quán)限位,。以0開頭,,這個(gè)是一個(gè)八進(jìn)制值。
oct函數(shù)強(qiáng)制對(duì)一個(gè)字符串按八進(jìn)制解釋,,不論前面有沒有0:
刪除空目錄,,可用rmdir函數(shù)。
rmdir glob "aa/*";	刪除aa/下所有空目錄,。
rmdir操作符對(duì)非空目錄操作會(huì)失敗,。所以要先用unlink刪除文件,再刪除目錄,。
修改權(quán)限
perl中有一個(gè)chmod函數(shù),,和unix shell中的chmod完成類似功能。
chmod 0755, "aa","bb";
perl中不接受符號(hào)權(quán)限表達(dá)式方式,,如+x,go=u-w等,。
改變所有者
chown函數(shù)可以改變一組文件的所有者和屬組。
chown 1004,100,glob "*.o";
可用getpwnam把用戶名翻譯成一個(gè)數(shù)字,,用getgrnam函數(shù)把組名翻譯成一個(gè)數(shù)字,。
改變時(shí)間戳
utime函數(shù)可修改文件的訪問時(shí)間和修改時(shí)間。
my $now = time;
my $ago = $now -24*60*60;	每天的秒數(shù)
utime $now,$ago,glob "*";	把訪問時(shí)間設(shè)為現(xiàn)在,,修改時(shí)間設(shè)為一天以前
第三個(gè)時(shí)間ctime的值在對(duì)文件做任何改變時(shí),,總被設(shè)為“現(xiàn)在”,,因此沒辦法用utime函數(shù)
來設(shè)置它。因?yàn)樵谀阍O(shè)置完后它會(huì)立即被重置為“現(xiàn)在”,,這是因?yàn)樗闹饕康木褪沁M(jìn)行
增量備份:如果文件的ctime比備份磁帶上的日期要新,,就說明又需要備份了。
使用簡單的模塊
File::Basename模塊	從文件名中抽取基名,,取不包括路徑的文件名,。
通過use命令聲明一個(gè)模塊
use File::Basename;
這樣,我們就有了一個(gè)basename函數(shù),。
my $name = "/usr/local/bin/perl";
my $basename = basename $name;	得到perl
該函數(shù)可用于多平臺(tái),,如windows。
該模塊中還有一個(gè)dirname函數(shù),,它把目錄名從一個(gè)完整文件名中分離出來,。
有選擇地使用模塊中的函數(shù)
當(dāng)你不需要模塊中的所有函數(shù),或模塊中的函數(shù)和你程序中子例程有沖突時(shí),,你可以在聲明
模塊時(shí)給模塊一個(gè)引入列表,,只包括需要的函數(shù)。
use File::Basename qw /basename/;	只要basename函數(shù),,不要其它函數(shù)。
use File::Basename qw //;		不要任何函數(shù),。
怎么會(huì)想要一個(gè)空列表呢,?這是因?yàn)椋幸胫皇鞘沟梦覀兡苁褂枚痰暮唵蔚暮瘮?shù)名,,
basename,dirname,。即使不引入這些名字,我們?nèi)钥梢允褂?,只是在沒有引入時(shí),,我們要用
全名來調(diào)用它,如:File::Basename::dirname,。
每個(gè)模塊都有缺省的引入列表,,查相關(guān)文檔有介紹。
File::Spec模塊
用來處理文件規(guī)范(file specification),。它是一個(gè)OO的模塊,。用小箭頭而不是::來引用函數(shù)。
$newname = File::Spec->catfile($dirname,$basename);
第十四章   進(jìn)程管理
通過perl直接啟動(dòng)其它程序,。
system函數(shù)
system "date";		啟動(dòng)unix系統(tǒng)的date命令,。
子進(jìn)程會(huì)運(yùn)行date命令,它將繼承perl的標(biāo)準(zhǔn)輸入,,標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤,。
system ‘ls -l $HOME‘;	注意是用單引號(hào),,因?yàn)?HOME是shell變量,否則,,shell就看不到
美元符號(hào),。表明要替換的符號(hào)。
system "long_time_command&";	把長時(shí)間運(yùn)行的程序放在后臺(tái),。
system ‘for i in *; do echo ==$1 ==; cat $i; done‘;	可以寫腳本
避免shell
調(diào)用system操作符時(shí)帶多個(gè)參數(shù),,此時(shí)shell就不會(huì)卷入。如:
system "tar","cvf",$aaa,@bbb;	第一個(gè)命令是tar,,其余的參數(shù)會(huì)一個(gè)一個(gè)傳遞給它,。
system的退出狀態(tài)基于子進(jìn)程的退出狀態(tài)。在unix中0表示正常,,非0表示出錯(cuò),。
unless (system "date") {	返回0表示成功
print "we gave you a date,ok!\n";
}
exec函數(shù)
與system差不多,system會(huì)生成一個(gè)子進(jìn)程,,exec是讓perl進(jìn)程本身去處理所要求的動(dòng)作,。
一般用system就可以了。
環(huán)境變量
當(dāng)你啟動(dòng)一個(gè)新進(jìn)程時(shí),,環(huán)境變量就被繼承下來了,。在perl中,通過特殊的%ENV散列得
到環(huán)境變量,,散列中每個(gè)鍵表示一個(gè)環(huán)境變量,。在你的程序剛開始執(zhí)行時(shí),%ENV就從父
進(jìn)程(通常是shell)繼承而來,。修改這個(gè)散列就改變了環(huán)境變量,,它又會(huì)被新進(jìn)程繼承。
$ENV {‘PATH‘} = "/home/mydir/bin:$ENV{‘PATH‘}";       設(shè)置新的環(huán)境變量,,增加了一個(gè)
路徑
delete $ENV{"IFS"};					刪除“IFS”這個(gè)路徑
my $make_result = system "make";			在新環(huán)境變量中執(zhí)行程序
使用反引號(hào)捕獲輸出
當(dāng)使用system and exec時(shí),,所啟動(dòng)命令的輸出都被送到perl的標(biāo)準(zhǔn)輸出上。有時(shí)我們需捕
獲這些輸出,。
my $now = `date`;
print "the time is now $now.";		已經(jīng)有換行符,,不用加\n。
與shell差不多,。但它把行尾去掉,,而perl的輸出包含\n。所以要得到同樣的效果,,需加上
chomp操作,。
在列表上下文中使用反引號(hào)
my $who_text = `who`;	標(biāo)量上下文,得到一個(gè)長字符串,。
my @who_lines = `who`;	列表上下文,,得到一個(gè)按行分開的數(shù)據(jù),。
文件句柄形式進(jìn)程
perl可以啟動(dòng)一個(gè)處理活動(dòng)狀態(tài)的子進(jìn)程。啟動(dòng)一個(gè)并發(fā)子進(jìn)程的語法是把命令當(dāng)做“文件
名”用在open調(diào)用中,,在命令之前或之后加一個(gè)豎線,,這是一個(gè)“管道”字符,因些,,這
通常被稱為管道打開(piped open),。
open DATE, "date|" or die "cannot pipe from date:$!";
豎線在右邊,其標(biāo)準(zhǔn)輸出與文件句柄DATE連接,,就像shell中的date | your_program,。
open MAIL, "|mail merlyn" or die "cannot pipe to mail:$!";
豎線在左邊,命令的標(biāo)準(zhǔn)輸入文件句柄MAIL連接,,就像shell中的your_program | mail,。
命令啟動(dòng)后是個(gè)獨(dú)立于perl的進(jìn)程。
要讀取一個(gè)為讀而打開的文件句柄,,我們只需進(jìn)行普通的讀:
my $now = <DATE>;
要想給郵件進(jìn)程發(fā)送數(shù)據(jù),,一人簡單的“帶文件句柄的打印”就可以了:
print MAIL "the time is now $now.";
用fork進(jìn)行深入和復(fù)雜的工作
用低級(jí)系統(tǒng)調(diào)用實(shí)現(xiàn) system "date";命令。
defined (my $pid = fork ) or die "cannot fork:$!";
unless ($pid) {
exec "date";
die "cannot exec date:$!";
}
waitpid($pdi.0);
發(fā)送和接收信號(hào)
向4201發(fā)送一個(gè)SIGINT,。
kill 2, 4201 or die "cannot signal 4201 with SIGINT:$!";
你也可用“INT”替代這里的2,,因?yàn)?號(hào)信號(hào)就是SIGINT。
信號(hào)0表示,,看看我能不能發(fā)一個(gè)個(gè)信號(hào),,但我并不想現(xiàn)在發(fā)送。因此可用以進(jìn)程探測(cè),。
unless (kill 0,$pid) {
warn "$pid has gone away!";
}
第十五章    字符串與排序
用index尋找子字符串在大字符串中出現(xiàn)的位置,。
$where = index($big,$small);
例子
my $where = index ("howdy world","wor")		where 是 6 .
index還有第三個(gè)參數(shù),,告訴index從后面某個(gè)指定的位置開始搜索,,而不是從開頭。
可用rindex函數(shù)找到子字符串最后出現(xiàn)的位置,。
my $last_slash = rindex ("/etc/passwd","/");	值是4
rindex也有可選的第三個(gè)參數(shù),,但此時(shí)給出的是允許的最大返回值。
用substr處理一個(gè)子字符串
substr操作符只作用于一個(gè)大字符串的一部分,,它看起來如下:
$part = substr($string,$initial_position,$length);
它取三個(gè)參數(shù):字符串值,、以零為基準(zhǔn)的初始位置(與index的返回值類似)和子字符串的
長度。返回值是一個(gè)子字符串:
my $mineral = substr ("hello world",6,5);	得到world
my $rock = substr "hello world,6,10000";	得到world,,第三個(gè)參數(shù)可超過實(shí)現(xiàn)的字符串長度,。
如果想確保到達(dá)字符串末尾,不論它多長或多短,,則只須省略第三個(gè)參數(shù),。
始初位置可以是負(fù)值,,意思是從字符串的末尾數(shù)起,即-1代表最后一個(gè)字符,。
index and substr可很好地配合工作,。如我們可以取出從字線l位置開始的一個(gè)子串:
my $long = "a very very long string";
my $right = substr($long,index($long,"l"));
還可以使用綁定操作符(=~)以限制某個(gè)操作符只作用于字符串的一部份。
substr($string,-20) =~ s/aa/bb/g;
但在實(shí)現(xiàn)代碼中不會(huì)需要這樣的功能,。
用substr and index能完成的工作多數(shù)也可以用正則表達(dá)式完成,。不過substr and index一般
會(huì)快一些。
四個(gè)參數(shù)版本的substr,,第四個(gè)參數(shù)就是做替換的子字符串,。
my $previous_value = substr($string,0,5,"Goodbye");
用sprintf格式化數(shù)據(jù)
sprintf 和 printf取一樣的參數(shù)(除了可選的文件句柄之外),但它返回請(qǐng)求的字符串而不是
打印它,。
my $date_tag = sprintf "%4d/%02d/%02d %2d:%02d",$yr,$mo,$da,$h,$m,$s;
在本例中,,$date_tag得到的東西類似于"2004/01/01 3:00:00"。
使用sprintf處理“錢數(shù)”
顯示2.50而不是2.5,,可用“%.2f”格式完成,。
my $money = sprintf "%.2f",2.499999";
如果你的“錢數(shù)”的太大以至于需要逗號(hào)來顯示它的大小,那么可以用以下例程實(shí)現(xiàn),。
sub money {
my $number = sprintf "%.2f",shift @_;		每次通過空循環(huán)時(shí)加一個(gè)逗號(hào)
1 while $number =~ s/^(-?\d+)(\d\d\d)/$1,$2/;	在合適的地方加上美元符號(hào)
$number =~ s/^(-?)/$1\$/;
$number;
第一行格式化第一個(gè)參數(shù)以獲得在小數(shù)點(diǎn)后準(zhǔn)確的兩個(gè)數(shù)字,。如果參數(shù)是數(shù)字12345678.9
那么我們的$number就是字符串"12345678.90"。
下一行使用一個(gè)while修飾符,,表示只要替換返回真值(表示成功),,循環(huán)體就被執(zhí)行,但
循環(huán)體什么都不做,。它可以有兩種其它寫法:
while ($number =~ s/^(-?\d+)(\d\d\d)/$1,$2/) {
1;
}
和
‘keep looping‘ while $number =~ s/^(-?\d+)(\d\d\d)/$1,$2/;
這個(gè)替換做了什么呢,?模式會(huì)匹配字符串的前面部份,不能匹配小數(shù)點(diǎn)后面的部份,。記憶$1
會(huì)得到"12345",$2會(huì)得到"678",,因此替換后會(huì)使得$number變成"12345,678.90"。如果替換
成功,,則循環(huán)重新開始,。這次,模式不能匹配逗號(hào)以后的部份,,因此$number變成
"12,345,678.90",。這樣,替換在每次通過空循環(huán)時(shí)添加一個(gè)逗號(hào),。接著再進(jìn)入一次循環(huán),,但
這次模式不能匹配,所以循環(huán)就結(jié)束,。在字符開頭的一個(gè)負(fù)號(hào)作用是把美元符號(hào)放在正確的
位置,。變樣$number就是"$12,345,678.90",。
高級(jí)排序
內(nèi)置的sort操作符按ASCII字母順序排序。如果要對(duì)組數(shù)值,,或大小寫無關(guān),,或存儲(chǔ)在散
列中的信息對(duì)一些條目進(jìn)行排序。那就要告訴perl你想要什么樣的順序,,方法就是寫一個(gè)
排序定義子例程,。如下一個(gè)數(shù)值排序子例程:
sub by_number {
if ($a < $b ) {-1} elsif ($a > $b) {1} else {0}
}
如果$a應(yīng)該$b之前,則返回-1,,如果$b應(yīng)該在$a之前,,則返回1,如果$a 和$b的順序無
關(guān)緊要,,則返回0,,如相等。
要使用排序子例程,,只須把它的名字放在關(guān)鍵字sort操作符和要排序的列表之間就可以了,。
my @result = sort by_number @some_number;
不需在子例程中聲明$a $b,如果這樣做了,,子例程就無法工作,。還有一種更簡單的寫法,
而且更有效率,。采用<=>操用符,。
sub by_number { $a <=> $b}
cmp是比效字符串的操作符。
sub ascii {$a cmp $b)
my @stings = sort ascii @any_string;
大小寫無關(guān)的比較
sub case_insensitive {"\L$a" cmp "\L$b"}	用\L強(qiáng)制把參數(shù)變成小寫
以“內(nèi)聯(lián)”的方式把排序子例程寫進(jìn)代碼中:
my @number = sort {$a <=> $b} @some_number;
如果按降序排序,,可用reverse寫成:
my @number = reverse sort {$a <=> $b} @some_number;
也可以把參數(shù)互換達(dá)到反序的目的:
my @number = sort {$b <=> $a} @some_number;
按值排序一個(gè)散列
my %score =("aa" => 195,"bb" => 201,"cc" => 40);
my @winners = sort by_score keys %score;
sub by_score { $score{$b} <=> $score{a} }
按照多個(gè)鍵排序
如果散列中有兩個(gè)相同的值,。那么可以按名字排序。
my @winners = sort by_score_and_name keys %score;
sub by_score_name { $score{$b} <=> $score{a} 	按數(shù)值分?jǐn)?shù)排序
or			加一個(gè)低優(yōu)先級(jí)的短路or操作符
$a cmp $b		按名字根據(jù)ASCII字母順序排序
}
排序子例程不是只能使用兩級(jí)排序,,允許多級(jí)排序,。如上例,多加幾個(gè)or操作符就可以了,。
第十六章	簡單數(shù)據(jù)庫
DBM文件和DBM散列
在每個(gè)有perl的系統(tǒng)都有一個(gè)已經(jīng)可用的簡單數(shù)據(jù)庫,,以DBM文件的形式存在,。這可讓你
的程序把數(shù)據(jù)存儲(chǔ)在一個(gè)文件或一對(duì)文件中以便快速查詢,。當(dāng)使用兩個(gè)文件時(shí),一個(gè)存放數(shù)
據(jù),,一個(gè)存放目錄,。
有些DBM的實(shí)現(xiàn)對(duì)文件中每個(gè)鍵和值的大小有一個(gè)1000字節(jié)的限制。但對(duì)文件中單個(gè)數(shù)
據(jù)項(xiàng)的數(shù)目沒有限制,,只要你有足夠的硬盤空間,。
打開和關(guān)閉DBM散列
要把一個(gè)DBM數(shù)據(jù)庫和一個(gè)DBM散列關(guān)聯(lián)起來,,即打開數(shù)據(jù)庫,可以使用dbmopen函數(shù),。
dbmopen (%DATA,"my_database",0644)
or die "cannot create my_database:$!";
第一個(gè)參數(shù)是散列的名字,,如果這個(gè)散列已經(jīng)有值了,那么在打開DBM文件后這些值都將
無法訪問,。
第二個(gè)參數(shù)是DBM數(shù)據(jù)庫名,,在硬盤上通常以一對(duì)擴(kuò)展名為.dir and .pag的文件存儲(chǔ),但在
這里不需要打上擴(kuò)展名,。
第三個(gè)參數(shù)是權(quán)限值,。被賦于打開的文件。
使用大寫散列名只是個(gè)傳統(tǒng),,和文件句柄一樣,。
DBM散列在程序運(yùn)行的全過程中一直打開。當(dāng)程序結(jié)束時(shí),,關(guān)聯(lián)被終止,。你也可以用
dbmclose關(guān)閉它
dbmclose (%DATA)
使用DBM散列
DBM散列與一般散列幾乎一樣工作??梢栽谏⒘兄刑砑?,刪除,保存數(shù)據(jù),。只是并非存在
內(nèi)存中,,而是在硬盤上。
$DATA("aa") = "test";	生成或更新一個(gè)元素
delete $DATA{"aa"};	刪除數(shù)據(jù)庫中一個(gè)元素
while (my($key,$value) = each(%DATA)) {
print "$key has value of $value\n";
}
訪問一個(gè)由c程序維護(hù)的DBM文件,,你就應(yīng)該知道C程序通常會(huì)在字符的末尾加一個(gè)
NUL("\0")字符,,原因是c使用NUL字節(jié)作為字符串尾標(biāo)志。DBM庫例程不需要這個(gè)NUL,,
因此NUL會(huì)被當(dāng)作數(shù)據(jù)的一部份被存儲(chǔ),。如果要和C程序合作,就必須在你的鍵和值后面
加一個(gè)NUL字符,,而把返回值末尾的NUL去掉從而使得數(shù)據(jù)變得有意義,。例如在一個(gè)unix
系統(tǒng)上的sendmail別名數(shù)據(jù)庫中搜索mymail。你可作以下操作:
dbmopen(my %ALL,"/etc/mail/aliases",undef) or die "no aliases?";
my $value = $ALL{"mymail\0"};		注意附加的NUL
$value =~ s/\0$//;			刪去結(jié)尾的NUL
print "my mail is headed for "$value\n";顯示結(jié)果
如果你DBM文件被多個(gè)進(jìn)程并發(fā)訪問,,如通過WEB來更新,,那么就需要一個(gè)附加的鎖文
件。具體內(nèi)容需查詢相關(guān)資料,。
在pack and unpack處理數(shù)據(jù)
pack函數(shù)取一個(gè)格式字符串和一組參數(shù),,然后把參數(shù)裝配置到一起構(gòu)成一個(gè)字符串,unpack
還原字符串。
my $buffer = pack ("c s l",31,1123,85858);
格式c,s,l代表char,short and logn,。所以第一個(gè)數(shù)字裝入一個(gè)字節(jié),,第二個(gè)數(shù)字裝入兩個(gè)字節(jié),
第三個(gè)數(shù)字裝入四個(gè)字節(jié),。格式字符可查詢
perlfunc手冊(cè),。
固定長度的隨機(jī)訪問數(shù)據(jù)庫
固定長度不是說文件本身,而是指單個(gè)記錄是固定長度的,,就好像關(guān)系數(shù)據(jù)庫中的定長字段,。
假如有一組記錄,用pack格式字符代表如下:
名字	40個(gè)字符	a40
年齡	單字節(jié)整數(shù)	C
分?jǐn)?shù)	5個(gè)雙字節(jié)整數(shù)	I5
日期	4字節(jié)整數(shù)	L
每個(gè)記錄共55個(gè)字節(jié),。
perl支持使用此類磁盤文件,。步驟如下:
1、為讀和寫打開一個(gè)磁盤文件,。
用"+<"模式open一個(gè)文件,,就對(duì)該文件有讀寫權(quán)限?!?lt;”只是有讀權(quán)限,。“+>”生成一個(gè)
新文件,,并對(duì)它有讀寫權(quán)限,。
2、在這個(gè)文件中移動(dòng)到任意位置,。
seek函數(shù)能在文件中移動(dòng)
seek (HEAD,55 * $n,0);
第一個(gè)參數(shù)是文件句柄,。
第二個(gè)參數(shù)是距文件頭的偏移量,以字節(jié)為單位,。
第三個(gè)參數(shù)是0,,是“從哪里開始”參數(shù),如果你尋址到一個(gè)相對(duì)于當(dāng)前位置的位置,,或相
對(duì)于文件尾的位置,,就可使用一個(gè)非0值,多數(shù)為0,。
一旦文件指針用seek定了位,,那么下次的輸入輸出操作將會(huì)從那個(gè)位置開始。
3,、按長度取出數(shù)據(jù),,而不是直到下一個(gè)換行符。
使用read函數(shù)讀取數(shù)據(jù),。
my $buf;	輸入緩沖區(qū)變量
my $number_read = read(HEAD,$buf,55)
讀出55個(gè)字節(jié)數(shù)據(jù)后,,可用unpack拆裝它們,以獲得具體信息,。
my ($name,$age,$score1,$score2,$score3,$score4,$score5,$when) = unpack"a40 C I5 L",$buf;
4,、按固定長度寫數(shù)據(jù)。
不是用write,,而是用print,。并用pack確保長度正確。以存入一個(gè)new_score和時(shí)間為例
print HEAD pack("a40 C I5 L",$name,$new_scroe,$score1,$score2,$score3,$score4,time);
可變長(文本)數(shù)據(jù)庫
#!/usr/bin/perl -w
use strict
chomp(my $date = `date`);	一個(gè)更好的辦法是使用localtime
@ARGV = glob "aa.dat" or die "no files found";
$^I = ".bak";		舊文件備份成.bak文件,,如果是空串,,則不生成備份,但不建議這樣用,。
while (<>) {
s/^aaa:*/aaa:change value/;	修改值
s/^bbb:.*\n//;			刪除
s/^ccc:.*/ccc:$date/;		更新日期
print;
}
該程序生成一個(gè)修改后的新文件,,文件名和舊文件一樣,舊文件被備份成.bak文件,。該程序
能在幾秒鐘內(nèi)更新幾百個(gè)文件,,功能相當(dāng)強(qiáng)大。
從命令行現(xiàn)場(chǎng)編輯
# perl -p -i.bak -w -e ‘s/aaa1/aaa/g‘ bbb*.dat
-p	告訴perl為你寫一個(gè)程序
-i.bak	同$^I設(shè)置,,生成.bak文件
-w	打開警告
-e	表示后面是可執(zhí)行代碼
最后一個(gè)參數(shù)表明@ARGV將包含匹配這個(gè)glob文件名列表,。一個(gè)完整的程序如下:
#!/usr/bin/perl -w
@ARGV = glob "bbb*.dat";
$^I=".bak";
while (<>) {
s/aaa1/aaa/g‘;
print;
}
如果代碼少,只有幾行,,采用命令行選項(xiàng)更方便,。
第十七章	一些高級(jí)Perl技術(shù)
用eval捕獲錯(cuò)誤
一種捕獲致命錯(cuò)誤的辦法,把代碼放在eval塊中,。
eval { $aa = $cc / $dd };	這樣,,即使$dd是零,也不會(huì)導(dǎo)程序崩潰,。
如果出錯(cuò),,程序會(huì)繼續(xù)運(yùn)行,并不崩潰,,$@變量包含了程序崩潰的出錯(cuò)信息,。如果沒有錯(cuò)
誤,$@為空,。它是一個(gè)有用的布爾值,。
print "an error occurred":$@" if $@;	如果出錯(cuò),則打印出錯(cuò)信息,。
eval 可嵌套
eval不能捕獲的問題有四種
1,、非常嚴(yán)重的錯(cuò)誤,導(dǎo)致perl本身崩潰,。
2,、eval塊中的語法錯(cuò)會(huì)在編譯時(shí)被抓住,不會(huì)在$@中返回。
3,、exit操作符立即終止程序,。
4、警告信息,。
用grep從一個(gè)列表中選擇條目
從一個(gè)大的數(shù)字列表中取得奇數(shù)條目,。
my @number = grep {$_ % 2 } 1..1000;
這行簡單的代碼就得到一個(gè)500個(gè)奇數(shù)的列表。它是如何工作的呢,?grep第一個(gè)參數(shù)是一個(gè)
塊,,其中$_表示列表中每個(gè)條目的占位符,該塊返回一個(gè)布爾值,。其余的參數(shù)是要搜索的條
目列表,。grep對(duì)列表中的每個(gè)條目計(jì)算一次表達(dá)式,如果為真就包括到結(jié)果列表中,。$_不斷
地由列表中的一個(gè)元素變成下一個(gè)元素,。就好像一個(gè)foreach循環(huán)。
grep是perl中的一個(gè)操作符,,同unix中的工具名grep同名,。能完成相同的工作,但更加強(qiáng)
大,。下面語句能把文件中提到test的行抓取出來:
my @test = grep {/\btest\b/i} <file>;
如果你選擇的僅僅是一個(gè)簡單的表達(dá)式,,而不是一個(gè)完整的塊,可以不用大括號(hào),,用一個(gè)逗
號(hào)隔開就可以了,。
my @test = grep /\btest\b/i,<file>;
用map轉(zhuǎn)換一個(gè)列表的條目
與grep相似,對(duì)列表中的每個(gè)條目都計(jì)算一次塊,,但塊的最后一個(gè)表達(dá)式不同,,它實(shí)際上
成為結(jié)果列表的一部份。
my @date = (4.22,4,33,5.323,78.2);
my @formatted_date = map {&big_money($_)} @date;
不加引號(hào)的散列鍵
如$score {aa},而不必寫成$score {"aa"}
這類不帶引號(hào)的簡單字符串被稱為裸字(bareword),。前提是大括號(hào)中除了裸字外沒有其它東
西,。
更強(qiáng)大的正則表達(dá)式
非貪婪數(shù)量符
我們?cè)诘诎苏轮幸姷降乃膫€(gè)數(shù)量符都是貪婪(greedy)的。意思是它們都盡可能多地進(jìn)行匹
配,。
+?	匹配一次或多次,,和加號(hào)一樣,但它傾向于匹配盡量少的次數(shù),。
*?	匹配0次或多次,,和*號(hào)一樣,但它傾向于匹配最少的次數(shù),。在html中去掉所有的<bold>
and </bold>標(biāo)記如果寫成:
s#<bold>(.*)</bold>#$1#g就不對(duì),,因?yàn)樾翘?hào)是貪婪的,,如果文件中我多個(gè)這樣的標(biāo)記,它
可能匹配第一個(gè)的<bold>和最后一個(gè)的</bold>,。
{3,10}?
??	匹配一次或0次,。
匹配多行文本
傳統(tǒng)的正則表達(dá)式只能用來匹配單行文本,perl可以匹配多行文本,,用/m匹配內(nèi)部換行符
的位置,。
切片
我們會(huì)碰到只操作一個(gè)給定列表中幾個(gè)元素的情況,,例如一個(gè)圖書館讀者的信息,,文件中每
行用六個(gè)冒號(hào)分隔。但我只需要其中的兩個(gè)信息,,這時(shí)我們就可以用切片的方法來處理:
while (<FILE>) {
chomp;
my @items = split /:/;
my($aa,$bb) = ($items[1],$items[5]);
....
}
可以直接寫成
my $aa = (split /:/)[1];
my $bb = (split /:/)[5];
也可以更高效和簡單地寫成
my ($aa,$bb) = (split /:/)[1,5];
切片是從列表中取出幾個(gè)項(xiàng)目最簡單的方法,。
數(shù)組切片
my @numbers =@names [1,2,3,4,9];
散列切片
my @three_scores = @scores{qw/aa bb cc/};

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多