學習perl(3)
學習Perl (3)
這幾天學習Perl,我的感覺是越到後面的內容越難一些。
子例程
1)定義子例程
定義你自己的子例程時,將會用到關鍵字sub、子例程的名稱(不含&符號)以及(花括號內)經縮排的構成子例程主體的程式程式碼塊:(子例程的定義可以放在程式中的任何地方)
#!/usr/bin/perl -w
sub marine {
$n += 1;
print "Hello,sailor number $n!n";
}
2)呼叫子例程
任何表示式中只要使用了子例程的名稱(加上&符號),就會呼叫子例程:&marine;
3)返回值
在Perl中,任何子例程都有返回值,子例程並沒有分成有返回值和沒有返回值兩種。
#!/usr/bin/perl -w
sub sum_of_fred_and_barney {
print "Hey,you called the sum_of_fred_and_barney subroutine!n";
$fred + $barney;
}
$fred = 3;
$barney = 4;
$c = &sum_of_fred_and_barney;
print "$c is $c.n";
$d = 3 * &sum_of_fred_and_barney;
print "$d is $d.n";
sub larger_of_fred_and_barney {
if ($fred > $barney){
$fred;
} else {
$barney;
}
}
$fred = 3;
$barney = 4;
$c = &larger_of_fred_and_barney;
print "The larger is $c.n";
3)引數
要傳遞引數列表到子例程裡,只要在子例程呼叫的後面加上被括住的列表表示式就行了:$n = &max(10,15); #本子例程的呼叫包含了兩個引數
當然得有變數來儲存這個列表,所以Perl會自動將引數列表儲存到名為@_的特殊陣列變數,在子例程執行期間內都有效。子例程可以訪問這個陣列,以判斷引數的個數和這些引數的值。所以這表示子例程的第一個引數儲存於$_[0],第二個引數儲存於$_[1],依次類推。
但是請特別注意,這些變數和$_變數毫無關聯,就像$dino[3]與$dino能彼此共存一樣。
sub max {
if ($_[0] > $_[1]) {
$_[0];
} else {
$_[1];
}
}
4)子例程裡的私有變數
在Perl裡,所有變數都被預設為全域性變數,也就是說,在程式裡的任何地方都可以訪問它們。但是你可以隨時執行my運算子來建立稱為詞法變數的私有變數:
sub max {
my($m,$n) = @_;
if ($m > $n) { $m } else { $n }
}
5)長度可變的引數列表
更好的&max例程
#!/usr/bin/perl -w
$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;
}
print "$maximum.n";
上面的程式碼使用了一般稱為高水位標記的演算法:大水過後,在最後一波浪消退時,高水位標記會表示所見過最高的水位。在本例中,$max_so_far記錄了最高水位標記,亦最大數字。
6)關於詞法(my)變數
事實上,詞法變數可以使用在任何塊內,而不僅限於子例程的塊。
還需要注意的是,my運算子並不會更改變數賦值時的上下文:
my($num) = @_; #列表上下文,和($num) = @_;相同
my $num = @_; #標量上下文,和$num = @_;相同
注意,在my不加括號時,只會宣告一個詞法變數而已:
my $fred,$barney; #錯,沒宣告$barney my ($fred,$barney); #兩個都宣告瞭
7)use strict編譯命令
所謂編譯命令,就是對編譯器的指示,告訴它關於程式程式碼的一些資訊。
要告訴Perl你願意接受某些限制,請將use strict這個編譯命令放在程式開頭(或在任何想要強制使用這些規則的塊或檔案裡): use strict; #強制使用一些良好的程式語言規則
這樣,撇開其他種種限制不談,Perl會要求你一定要用my來宣告每個新變數。當然,此限制只適用於新建立的變數。根據大部分人的建議,比整個螢幕長的程式都應該加上use strict。
8)return運算子
在子例程裡,return運算子會立即返回某個值:
#!/usr/bin/perl -w
use strict;
my @names = qw/ fred barney betty dino wilma pebbles bamm-bamm /;
my $result = &which_element_is("dino", @names);
sub which_element_is {
my($what,@list) = @_;
foreach (0..$#list) {
if ($what eq $list[$_]){
return $_;
}
}
-1;
}
寫Perl程式時return最常見的用法:馬上返回某個值,而不要執行子例程的其餘部分。
9)省略&符號
不要將子例程的宣告放到子例程的呼叫之後,不然編譯器就無法知道division的意義何在。
真正的陷阱是,假如這個子例程與Perl內建函式同名,你就必須適用&符號來呼叫:
#!/usr/bin/perl -w
use strict ;
sub chomp {
print " Munch, munch!n";
}
&chomp; #&符號不可省略!
所以,真正的省略規則如下:除非你知道所有Perl內建函式的名稱,否則請務必在呼叫函式時使用&符號!
10)返回非標量值
子例程不僅可以返回標量值,只要在列表上下文中呼叫它,它就可以返回列表值:
#!/usr/bin/perl -w
sub list_from_fred_to_barney {
if ($fred < $barney) {
$fred..$barney;
} else {
reverse $barney..$fred;
}
}
$fred = 11;
$barney = 6;
@c = &list_from_fred_to_barney;
print "@c.n";
習題:
1)寫一支名為&total的子例程,用來返回一串數字的總和:
#!/usr/bin/perl -w
use strict;
sub total {
my $sum;
foreach (@_) {
$sum += $_;
}
$sum;
}
my @fred = qw{ 1 3 5 7 9 };
my $fred_total = &total(@fred);
print "The total of @fred is $fred_total.n";
print "Enter some numbers on separate lines:";
my $user_total = &total(
print "The total of those number is $user_total.n";
2)利用前一題的子例程,寫一支程式來計算從1到1000的數值的總和:
#!/usr/bin/perl -w
use strict;
sub total {
my $sum;
foreach (@_) {
$sum += $_;
}
$sum;
}
my @fred = 1..1000 ;
my $fred_total = &total(@fred);
print "The total of @fred is $fred_total.n";
參考答案如下:
#!/usr/bin/perl -w
use strict;
sub total {
my $sum = 0;
foreach (@_) {
$sum += $_;
}
$sum;
}
print "The number from 1 to 1000 add up to:",&total(1..1000),".n";
3)寫一支名為&above_average的子例程,用來傳入一串數字並返回所有大於平均值的數字:
#!/usr/bin/perl -w
sub total {
my $sum = 0;
foreach (@_) {
$sum += $_;
}
$sum;
}
sub average {
if (@_ == 0) { return }
my $count = @_;
my $sum = &total(@_);
$sum/$count;
}
sub above_average {
my $average = &average(@_);
my @list;
foreach $element (@_) {
if ($element > $average) {
push @list, $element;
}
}
@list;
}
my @fred = &above_average(1..10);
print "@fred is @fredn";
print "(Should be 6 7 8 9 10)n";
my @barney = &above_average(100,1..10);
print "@barney is @barneyn";
print "(Should be just 100)n";
輸入與輸出
1)讀取標準輸入
在標量上下文中使用
#!/usr/bin/perl -w
while (defined($line =
print "I saw $line";
}
#!/usr/bin/perl -w
while (
print "I saw $_";
}
#!/usr/bin/perl -w
while (defined($_ =
print "I saw $_";
}
在列表上下文中執行整行輸入運算子,它會返回一個列表,其中包含(剩下來的)所有輸入內容,每個列表的元素代表一行輸入內容:
#!/usr/bin/perl -w
foreach (
print "I saw $_";
}
while迴圈和foreach迴圈的區別:在while迴圈裡,Perl會讀取一行輸入,把它存入某個變數並且執行迴圈的主體,接下來,它會回頭去尋找其他的輸入行;但是在foreach迴圈裡,整行輸入運算子會在列表上下文中執行(因為foreach需要逐項處理列表的內容),為此,在迴圈能夠開始執行之前,它必須先將輸入內容全部讀進來。因此,最好的做好是儘量使用while迴圈的簡寫,讓它每次處理一行。
2)從鑽石運算子輸入
如果想寫出用法像cat、sed、awk、sort、grep、lpr等工具的Perl程式,鑽石運算子”<>”將會是你的好幫手。程式的呼叫引數通常是命令列上跟在程式名稱後面的幾個“單詞”:
$ ./my_program fred barney betty #命令列引數代表依次處理的數個檔案的名稱
若不提供任何呼叫引數,程式應該改寫成處理標準輸入流。但有個特例,如果某個引數是連字元(-),那也代表標準輸入。讓程式以這種方式執行的好處,就是你可以在執行時指定程式的輸入來源。鑽石運算子是整行輸入運算子的特例,不過它並不是從鍵盤取得輸入,而是從使用者想要的輸入來源取得:
#!/usr/bin/perl -w
while (defined($line = <>)) {
chomp($line);
print "It was $line that I saw!n";
}
簡寫:#!/usr/bin/perl -w
while (<>) {
chomp; #chomp的預設用法,不加引數時,chomp會直接作用在$_上。
print "It was $_ that I saw!n";
}
3)呼叫引數
嚴格來說,鑽石運算子其實不會真的去檢查呼叫引數,直譯器事先建立的特殊陣列,其內容就是呼叫引數所組成的列表。鑽石運算子如何決定該使用哪些檔名?方法如下:它會查詢@ARGV,如果它找到的是空列表,就會改用標準輸入流;否則,就會使用@ARGV裡的檔案列表。
4)輸出至標準輸出
#!/usr/bin/perl -w
$name = "Larry Wall" ;
print "Hello there,$name,did you know that 3+4 is",3+4,"?n";
輸出陣列和替換陣列是兩回事:
print @array; #輸出列表中的專案,各個專案之間沒有空格
print “@array”; #輸出一個字串(內容是陣列替換的結果),專案間以空格隔開
一般來說,如果陣列裡的元素包含換行符號,那麼只要直接將它們輸出來就可以了;通常在使用引號的場合,字串後面都應該加上n。
print <>; #’cat’的原始碼 print sort <>; #’sort’的原始碼
print的呼叫看起來像函式呼叫,函式呼叫:print (2+3);
print的返回值不是“真”就是“假”,代表print是否執行成功。除非發生了I/O錯誤,否則一定會執行成功:$result = print(“Hello world!n”);
#!/usr/bin/perl -w
$result = print("Hello world!n");
print "The result is : $result.n";
如果print(或其他函式名稱)後面接著一個左括號,請務必在函式的所有引數之後也有相應的右括號。
省略括號的問題: print (2+3)*4 #錯 print ((2+3)*4); #正確
5)用printf格式化輸出結果
printf運算子的引數包括“格式字串”及“所要輸出的資料列表”,後面的列表裡的專案的個數應該要和轉換的數目一樣多,否則就會無法正常執行。
printf可用的轉換格式很多,如%g、%s、%f、%d等:
#!/usr/bin/perl -w
printf "in %d days!n",17.85; #輸出結果為in 17 days! 無條件捨去小數點後的數字
6)檔案控制程式碼
檔案控制程式碼就是Perl程式裡的某個名稱,代表Perl程式與外界之間的輸入/輸出聯絡。它是“聯絡”的名稱,不一定是檔名。建議全部使用大寫字母來命名檔案控制程式碼。Perl保留了6個具有特殊用途的檔案控制程式碼名稱:STDIN、STDOUT、STDERR、DATA、ARGV、ARGVOUT。
標準的STDERR通常是使用者的螢幕,但可以將STDERR以如下的shell命令送到某個檔案:
開啟檔案控制程式碼
當你需要其他普通的檔案控制程式碼時,請使用open運算子告訴Perl,要求作業系統為你的程式和外界開啟一座橋樑:open CONFIG, “,dino”; open LOG, “>>logfile”;open BEDROCK,”>fred”;
不良檔案控制程式碼
如果你嘗試從不良檔案控制程式碼(即沒有完全開啟的檔案控制程式碼)來讀取資料,將會立刻讀到檔案結尾。如果試圖將資料寫入不良檔案控制程式碼,這些資料將無聲無息地被丟棄掉。可以避免:一開始就用-w選項,或者warnings編譯命令來啟用警告資訊。
關閉檔案控制程式碼
當不再需要時,可以使用close運算子來關閉檔案控制程式碼:close BEDROCK;
7)用die來處理嚴重錯誤
die函式會輸出你指定的資訊(到此類資訊該去的標準錯誤流裡),並且讓你的程式在非零的狀態下立即終止。通常,對於程式的結束狀態來說,零代表成功,非零代表失敗。
Perl特殊變數“$!”,程式錯誤資訊。
if ( !open LOG,">>logfile") {
die "Cannot create logfile:$!";
}
一個經驗法則就是,用來指示用法錯誤的資訊裡可以加上結尾的換行符,但若想在除錯過程中追蹤相關的錯誤,就不要加上換行的結尾符。請一定檢查open的返回值,因為之後的程式程式碼必須在檔案開啟成功時才能順利進行。
用warn送出警告資訊
warn函式不會停止程式的執行。
8)使用檔案控制程式碼
當檔案控制程式碼以讀取模式開啟後,你可以輕易的從它讀取一行資料,就像從STDIN讀取標準輸入流一樣。
以寫入或新增模式開啟的檔案控制程式碼,可以在print或printf函式中使用。使用時,請直接放在關鍵字之後,引數列表之前:print LOG “Captain’s log,stardate 3.14159n”;
改變預設的輸出檔案控制程式碼
重新開啟標準的檔案控制程式碼
習題
1)寫一支功能跟cat類似的程式,但是將各行反序輸出:
#!/usr/bin/perl -w
print "Please enter some lines,then press Ctrl+D!n";
print reverse<>;
參考答案如下:
#!/usr/bin/perl -w
print reverse<>;
2)寫一支程式,要求使用者分行鍵入各個字串,然後以20個字元寬、向右對齊的方式輸出每個字串:
#!/usr/bin/perl -w
print "Please enter some lines,each line for one,then press Ctrl+D:n";
chomp(my @lines =
print "1234567890" x 7,"12345n";
foreach(@lines) {
printf "%20sn",$_;
}
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/21256317/viewspace-776983/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Perl語言學習(四)Perl控制結構
- Perl學習筆記(五)——關聯陣列筆記陣列
- perl
- 學習3
- Java學習(3)Java
- java學習3Java
- Python 學習3Python
- 強化學習-學習筆記3 | 策略學習強化學習筆記
- perl的logwrapperAPP
- Perl&LWP
- perl指令碼指令碼
- 使用perl cpan
- perl 安裝
- 3/8學習程序
- 3/13學習程序
- 3/25學習程序
- 3/19學習程序
- Vue3學習Vue
- 機器學習-3機器學習
- Protocol Buffers 3 學習Protocol
- perl+xml+iniXML
- Perl Catalyst 倒出 ExcelExcel
- Perl常用語法
- shell學習總結-3
- tensorflow學習筆記3筆記
- Vue學習筆記3Vue筆記
- PHP學習3——陣列PHP陣列
- 3/7學習進度
- 3/5學習進度
- javaweb學習之路(3)CookieJavaWebCookie
- mysql學習筆記3MySql筆記
- Vue 3 學習筆記Vue筆記
- FreeRTOS學習隨記-3
- 笨方法學Python3 習題3Python
- [20231130]快速刪除大量檔案測試(perl版本)3.txt
- WinUI 3學習筆記(3)—— ComboBox & DropDownButton & SplitButtonUI筆記
- 【機器學習基礎】無監督學習(3)——AutoEncoder機器學習
- perl分析apache日誌Apache
- perl替換特殊字元字元