Perl 語言學習 – 入門篇
入門篇包括但不限于以下内容
- Perl 簡介
- 版本曆史
- 第一個Perl程式
- Perl的基本資料類型
- Perl的運算操作符和判斷操作符
- Perl的數組操作
- Perl的控制結構語句
- Perl的子程式
注:盡管本文中沒有提及邏輯控制符,但Perl的邏輯控制符與C 或者 JAVA 的邏輯控制符号 基本一緻, 都支援與或非的操作 也就是 ! | & 這幾個符号,使用上也沒有太大差異。因而本文中就此略過,如有需要請自行查閱相關文檔
文章目錄
- Perl 語言學習 -- 入門篇
-
- 1 Perl 介紹
- 1.1 Perl 版本
-
- 1.1.1 曆史版本
- 1.1.2 主要版本分支 Strawberry Perl 與 ActiveState Perl
- 1.1.3 CPAN
- 1.2 Perl 安裝
- 2 第一個Perl程式
- 3 Perl的資料
-
- 3.1 數字
-
- 3.1.1 數字運算操作符
- 3.1.2 數字比較操作符
- 3.2 字元串
-
-
-
- 字元串的單雙引号差別
-
- 3.2.1 字元串運算操作符
- 3.2.2 字元串比較操作符
- 3.2.3 字元串的函數操作
- 3.2.4 數字與字元串的自動運算和類型轉換
-
- 3.3 布爾值
-
- 3.4 變量
- 3.4.1 變量的指派
- 3.4.2 變量的作用域
-
- 1.包域全局 our
- 2.臨時全局 local
- 3.私有局部my
- 4.持久局部state
- 3.5 清單和數組
-
- 3.5.1 數組
- 3.5.2 清單
- 3.5.3 數組和棧Stack
- 3.5.4 字元串的數組内插
- 3.5.5 數組的常用函數
- 4 Perl的控制結構
-
- 4.1 判斷結構
-
- 4.1.1 If 和 unless
- 4.2 循環結構
-
- 4.2.1 while 和 until
- 4.2.3 foreach 和 for
- 5 Perl的子程式
1 Perl 介紹
- Unix系統自帶Perl,被稱為“Unix工具箱”
- 被稱為“實用摘錄與報表語言” Practical Extraction and Report Language
- 也被稱為“病态這種式垃圾清單器” Pathologically Eclectic Rubbish Lister
- Perl 座右銘: There’s More Than One Way To Do It !
- Perl擅長于文本處理和系統管理,不适合于實時嵌入式系統程式設計、作業系統底層開發(比如驅動程式開發)、複雜的多線性共享記憶體應用以及極度大的應用。
- Perl的發明曆史
- Larry想為類似新聞討論區的檔案體系寫一個Bug彙報系統而發明的**通用的多用途工具**
- 是由C以及sed、awk、Unix shell及其它語言演化而來的一種語言。
- Perl是一種為掃描任意的文本檔案,從這些文本檔案中擷取資訊,基于這些資訊列印報表而優化的語言。
- 旨在實用(易用、高效、完整)而不是漂亮(優美、小巧)。
- Perl的特點
- 優點
- 簡單好用
- 不受限制
- 不限制資料大小,僅受限于計算機存儲
- 幾乎所有工作都能用Perl完成
- 性能優秀
- 可移植性:大多數作業系統支援Perl
- 子產品擴充
- 函數
- 缺點
- 代碼醜(吉祥物是駱駝 -> Useful and ugly)
- 多種語言集合導緻的混亂(四不像)
- 可讀性差
- 優點
- 一些特點的記憶增強
- Perl程式的長度大約是等效C程式的 30% - 70%
- 适合用于 在三分鐘寫出“雖然難看但是能用”的一次性程式
- 擅長處理“約有90%與文字處理有關”的問題
嘗試用一句話描述Perl
- 這也行?
嘗試用一個詞描述Perl
- 天馬行空
1.1 Perl 版本
1.1.1 曆史版本
沒有查閱到相關資料,後續補充
1.1.2 主要版本分支 Strawberry Perl 與 ActiveState Perl
- 檔案大小不同
- Strawberry Perl:trawberry Perl 下載下傳的安裝檔案有 80多M。
- Active Perl:ActiveState Perl 隻有20M 左右
- 内容不同
- Strawberry Perl:Strawberry Perl 裡面有多包含一些 CPAN 裡的子產品。
- Active Perl:含了包括有 Perl for Win32、Perl for ISAPI、PerlScript、Perl Package Manager四套開發工具程式,可以讓使用者編寫出适用于unix,windows,linux系統的的CGI程式。
- 特點不同
- Strawberry Perl:用于Windows的100%開源Perl,使用來自CPAN的子產品不需要二進制包。
- Active Perl:ActiveState提供了一個免費的社群版本和一個商業支援的Perl用于Win32和Perl的二進制分布。
1.1.3 CPAN
Comprehensive Perl Archive Network
Perl綜合典藏網 ( http://search.cpan.org/ )
perl 的子產品擴充,用于下載下傳基于perl的各種擴充子產品及文檔資料等。
CPAN也需要額外安裝
yum install -y perl-CPAN
cpan的使用同資料庫類似,需要進入相應的操作界面, 使用 perl -MCPAN -e shell 進入該操作界面
具體的子產品和安裝指令後續會聊到。
1.2 Perl 安裝
https://www.perl.org/get.html 登入官網下載下傳對應版本安裝,列印版本驗證安裝
perl -v
2 第一個Perl程式
學習過 shell 腳本語言的程式員将會在perl的學習上有所助益。
Perl是一個純文字檔案,可以用任意的文本編輯器來編寫Perl程式,例如txt,vm/vim,notepad等
mkdir -p /data/test/
vim /data/test/HelloWorld.pl
鍵入
#!/usr/bin/perl
print "Hello world!\n";
儲存後使用 perl 運作這個檔案 。
注:如果使用非管理者使用者,請注意目前使用者是否有執行權限
perl /data/test/HelloWorld.pl
你可以看到程式會輸出相應的字元
繼續閱讀的一些補充知識點 -> 給剛接觸腳本語言的同僚
Perl 的 use 關鍵字,你在本文的剩餘部分會頻繁地看到 use 5.014; use warings; use utf8; use strict 等代碼,use 關鍵字實際上是對Perl 程式子產品的裝載,這是Perl可插拔式程式設計的關鍵用法。
上述代碼中例如 use 5.014 表示使用 Perl 5 版本号 14 的支援,say 函數在該版本才能夠正常使用。
關于use 關鍵字,還有很多可以展開的,但是現在你隻需要記住它被用于引入Perl 程式的子產品支援。
關于Perl use 關鍵字,這裡提供一些參考文檔:
- http://blog.chinaunix.net/uid-608135-id-4439772.html 這裡解釋了 use 關鍵字的底層實作和它的用法
- http://bbs.eetop.cn/thread-613055-1-1.html 這裡提到了 use 關鍵字 和 require 關鍵字的執行階段不同
- #!/usr/bin/perl , 你會注意到每一個Perl程式頭部的這行字。如果你不熟悉Linux 和腳本語言,也許會對它感到困惑。這是 腳本語言 在 Linux作業系統中的規約,用于告訴作業系統,執行該檔案時調用何種解釋器。你可以在上面的編寫的第一個程式中看到這個差別
- 這個調用過程指的是 直接運作該腳本檔案時,例如
沒有任何字首指向目前檔案夾下的test.pl 腳本,作業系統會從第一行聲明的解釋器路徑取查找解釋器,用該解釋器執行這個腳本。(使用這種方式需要給檔案賦予權限)./test.pl
- 如果指令程式設計
顯式地聲明了執行腳本的解釋器,那麼頭部行沒有寫也可以。(使用這種方式可以繞過權限限制)perl ./test.pl
3 Perl的資料
包括以下内容
- 兩種基本資料結構(浮點數和字元串)
- 資料的運算和比較操作符
- 浮點數和字元串的類型轉換
- 布爾值的定義 undef , 0 , “”
- 變量的指派及其作用域
- 清單和數組及其指派
- 清單和數組的常用操作符
- pop
- push
- shift
- unshift
- splice
- reverse
- sort
- each
3.1 數字
Perl内部不存在整數值,所有數字都将被存儲為“雙精度浮點數”(gcc編譯的double類型),
可以直接用整數表示。例如:5 --> 解釋為 5.00
注:Perl 内部會使用整數,但程式設計人員無需關心,其次Perl可以使用integer編譯指令編譯整數。
Perl 允許在整數中間插入 下劃線 _ , 例如表示一個銀行卡, 6217_0013_0000_0992_328, 這樣看起來就很清楚(如不需要計算,此類資料建議使用字元串表示)
3.1.1 數字運算操作符
Perl支援加減乘除和模運算以及幂運算等
數字運算操作 | 操作符 | 示例 | 示例操作結果 |
---|---|---|---|
加法 | + | 2 + 3 | 5.00 |
減法 | - | 5.1 - 2.4 | 7.50 |
乘法 | * | 1 * 2 | 2.00 |
除法 | / | 14 / 7 | 2.00 |
模運算 | % | 5 % 2 | 1.00 |
幂運算 | ** | 2 ** 3 | 8.00 |
3.1.2 數字比較操作符
數字比較操作 | 操作符 | 示例 | 示例操作結果 |
---|---|---|---|
相等 | == | 1 == 1 | 真 |
不等 | != | 1 != 1 | 假 |
小于 | < | 1 < 1 | 假 |
大于 | > | 1 > 1 | 假 |
小于或等于 | <= | 1 <= 1 | 真 |
大于或等于 | >= | 1 >= 1 | 真 |
關于真假的布爾定義,稍後的章節會說明
3.2 字元串
Perl 的字元串是被單引号’’ 或 雙引号 “” 包圍的文本,例如: ‘a character’, “still character”;
Perl 的字元串長度無限制。(展現了Perl 原則之一:無記憶體限制) 0 - Memory-Max
Perl 字元完全支援 Unicode。(需要聲明編碼格式)
use charset 函數,聲明檔案的編碼格式
encoding(charset) 函數,指定特定行為的編碼格式
字元串的單雙引号差別
- 單引号 ’ ’
- 單引号中單引号和反斜線 / 字元除外,單引号内所有字元都代表它們本身。
- 要表示反斜線時,需要連續兩個反斜線,要表示單引号本身,則将反斜線接着單引号。
- 雙引号 " "
- 雙引号中轉義符 \ 有效,轉義符的通常應用如 \n 換行, \r 回車, \u \l 下個字母大小寫等等
- 且能夠使用$内插一個變量到字元串中
#!/usr/bin/perl
use 5.014;
# 單引号中轉義符隻能用于轉義反斜線本身和單引号
print '\n隻是\n';
print "\n";
print '輸出一個單引号 \',在輸出一個反斜線\\';
print "\n";
# 雙引号中轉義符\有效,且能夠使用$内插一個變量到字元串中
my $sum = 5 + 3;
print "5 + 3 = $sum \n";
print "\uhello \uworld! \n";
3.2.1 字元串運算操作符
. 點可以作為字元串的連接配接操作符,如下
#!/usr/bin/perl
print "hello " . 'world' . "/n"; # 輸出 hello world [換行符]
x 操作符可以重複輸出相同的字元,如下
重複次數在使用前會先取整,去掉小數位,重複次數小于等于0時,生成空字元串
#!/usr/bin/perl
print "perl " x 3; #輸出 perl perl perl
print "perl " x 2.8; #輸出 perl perl
print "perl " x 0; #輸出 [空字元串]
兩者可以結合使用, 例如
#!/usr/bin/perl
print "perl " x 3 . "\n"; #輸出 perl perl perl [換行符]
3.2.2 字元串比較操作符
同樣支援六種比較操作,但符号與數字不相同。
字元比較操作 | 操作符 | 示例 | 示例操作結果 |
---|---|---|---|
相等 | eq | “a” eq “a” | 真 |
不等 | ne | “35” ne “35.0” | 真,按照字元比較 |
小于 | lt | “b” lt “a” | 真, 按照字母順序表 |
大于 | gt | “aa” gt “a” | 真, 按照字元長度 |
小于或等于 | le | “aa” le “aa” | 真 |
大于或等于 | ge | “aa” ge “aa” | 真 |
3.2.3 字元串的函數操作
-
index 查找子字元串
基本格式: index($STRING, matchString, [start_index])
- $STRING 必選: 要查找的目标字元串
- matchString 必選: 要查找的字元
- start_index 非必選 :從目标字元串的何處下标開始查找比對
查找指定字元串在目标字元串中的相對位置,傳回比對到的下标值, 未比對到則傳回 -1
#!/usr/bin/perl my $stuff = "hello world"; my $where = index $stuff, "world"; # $where = 6 my $where1 = index $stuff, "l"; # $where1 = 2 my $where2 = index $stuff, "l", $where1 + 1; # $where2 = 3 my $where3 = index $stuff, "l", $where2 + 1; # $where3 = 9 my $where4 = index $stuff, "l", $where3 + 1; # $where4 = -1
-
substr 截取字元串
基本格式: substr($STRING, start_index, [sub_length])
- $STRING 必選 :目标字元
- start_index 必選: 開始截取的字元串下标
- sub_length 非必選: 截取長度
目标字元串被截取後并不會有任何變化
#!/usr/bin/perl use 5.010; my $str = "I solemnly swear that I am up to no good" my $ret1 = substr $str, 20; # $ret1 = I am up to no good say $ret1 . "\n" . $str; # $str還是等于原文 my $ret2 = substr $str, -4, 4; # $ret2 = good say $ret2 . "\n" . $str; # $str還是等于原文
-
printf 和 sprintf格式化字元串
基本格式:printf(pattern, $String…)
- pattern 必選 : 格式化語句,以 % 開頭的字元,每個%号對應一種格式,同時将對一個參數進行格式化
- $String… 必選 : 要格式化的目标字元,可能有多個,與pattern格式化語句的個數相對應
printf 與 sprintf有相同的參數和句柄,printf将直接把字元經過格式化後列印到指令行,而sprintf将傳回格式化後的字元而不進行列印
printf 同java的格式化輸出和C的格式化輸出基本是一緻的。
#!/usr/bin/perl # %g 表示按需要自動選擇浮點數、整數或者指數形式 # 2.5 3 1.0683e+29 printf "%g %g %g\n", 5/2, 51/17, 51**17; # %d 表示十進制整數格式,将自動去掉小數點後的數字 # 2 printf "%d\n", 2.5; # %6d 6表示定長字元,在輸出日志等消息時頻繁使用 # ······2 (·表示空格) printf "%6d\n", 2;
3.2.4 數字與字元串的自動運算和類型轉換
運算操作符決定數字與字元串的結合産物,使用數字操作符連接配接則所有被連接配接的變量作為數字,使用字元操作符連接配接則被連接配接的變量被視為字元,如下所示
#!/usr/bin/perl
use 5.014;
say "1" + 2; #輸出3
say "1" . 2; #輸出12
say "1" x 3 + 2; #輸出113 重複字元次數先運作
say "1" . 3 + 2; #輸出15 加法先運作
say "1" x 3 * 2; #輸出222 重複字元次數先運作
say "1" . 3 * 2; #輸出16 乘法先運作
注:
- 操作符優先級,參考文檔,常用的如右側所示: () 高于 ++ – 高于 * / % x 高于 + - .
- 字元自動轉換數字規則,首字元如果不為數字,則視為0,反之則取數字,直到比對到不為數字的字元。如:
代碼示範
- 12kjsdha2321 會被視為 數字 12。
- lksjdlak123 會被視為 數字 0。
#!/usr/bin/perl use 5.014; say "ksjdhalkd23" * 12; # 輸出 0 say "12ioqwnk3354" * 2; # 輸出24
3.3 布爾值
Perl 沒有明确的兩個标量值來定義真假
關于真假的定義是以假來定義的,下面這些都是假的值,除此之外,其他值都為真值
- undef - 表示未定義的值.
- 0 - 數字0,即使你寫成000或者0.0也同樣.
- ‘’ - 空字元串.
- ‘0’ - 隻包含一個0字元的字元串.
如下示例
#!/usr/bin/perl
use 5.014;
# 0為假
if(!0) {
say "hello";
}
# 空字元為假
if(!"") {
say "world";
}
# 任何非空的字元都為真
if('asdjkhasdk') {
say "anyway";
}
# 任何非0的數字都為真
if(5646545) {
say "everything is ok";
}
# undef 是假
if(undef == 0) {
say "undefined == false "
}
3.4 變量
指存儲值的容器,同其他程式設計語言的變量。
使用 $ 聲明一個變量
命名區分大小寫,字母或下劃線_開頭,可以由大小寫字母,數字,下劃線構成。
#!/usr/bin/perl
$variable1 = 1; #聲明一個數字變量
$usr_variable = 1; #使用下劃線連接配接多個單詞的變量
$usrVariable = 1; #使用駝峰命名法
$USER_VARIBALE_CONSTANT = 1; #!!!不建議使用全大寫的,可能與Perl保留的特殊變量名稱沖突
3.4.1 變量的指派
使用 = 号連接配接 變量 和 标量完成指派
#!/usr/bin/perl
$variable = "value";
字元變量和數字變量的操作符與标量相同,此外還支援雙目指派操作符
如下所示
#!/usr/bin/perl
use 5.014;
# 加等于操作
my $num1;
$num1 = $num1 + 1;
$num1 += 1;
say $num1;
# 輸出2 0 + 1 + 1 = 2
# 減等于操作
my $num2;
$num2 = $num2 - 1;
$num2 -= 1;
say $num2;
# 輸出 -2 0 - 1 - 1 = -2
# 乘等于操作
my $num3 = 1;
$num3 = $num3 * 2;
$num3 *= 2;
say $num3;
# 輸出4 1 * 2 * 2 = 4
# 除等于操作
my $num4 = 1;
$num4 = $num4 / 2;
$num4 /= 2;
say $num4;
# 輸出0.25 1 / 2 / 2 = 0.25;
# .等于操作(連接配接字元)
my $str1 = "one_";
$str1 = $str1 . "two_";
$str1 .= "three";
say $str1;
# 輸出 one_two_three;
# x等于操作(字元串的重複次數操作)
my $str2 = "yo ";
$str2 = $str2 x 2;
$str2 x= 2;
say $str2;
# 輸出 yo yo yo yo;
3.4.2 變量的作用域
轉載自 https://blog.csdn.net/henjay724/article/details/8457556#
考慮到示例不能完全展現關鍵字的主要作用和差別,對轉載的内容中示例部分做了修改
由于原文有部分内容錯誤,這裡也做出了修改。例如local不能聲明一個新的變量,這裡經過實驗是可以,因而删除。此外還添加了部分内容以補充。
知識點概要:
- 變量範圍分為兩類:全局、局部
- 全局變量标準(our)關鍵字、局部私有變量(my)關鍵字
- 局部本地變量(local)關鍵字、持久性私有變量(state)關鍵字
在Perl中,所有的變量、子程式和其他可以被命名的實體預設都擁有包作用域(亦稱“全局作用域”),也就是說它們存在于目前包的符号表中。可以在腳本檔案中通過package 函數聲明包名
如果不聲明包名,則預設為main包。
如果沒有關鍵字聲明變量,Perl會預設變量為全局變量,但如果啟用了 use strict 指令強制規定,則Perl會強制要求必須先聲明變量後才可使用變量。
1.包域全局 our
our操作符用于顯式地建立包作用域變量。
#!/usr/bin/perl
use 5.010;
# 關鍵字our
sub subroutine1{
say $var; #得到全局的var變量
$var +=1;
say $var;
&subroutine2;
}
sub subroutine2{
$var +=1; #得到全局的var變量
say $var;
}
our $var =1; #全局, 作用域為包
&subroutine1; #輸出1\n 2\n 3\n
say $var; #輸出3\n
注1:our操作符是在Perl 5時代被引入的,Perl 4時代變量均為全局,且不需聲明。到了Perl 5時代為避免變量混亂,引入了use strict指令強制規定必須聲明變量,而our操作符就是定義了一個看起來像詞法作用域的全局變量,進而通過strict指令限制。
注 2 :如果全局變量已存在,則 our 的作用是聲明這個全局變量(類似于 C 中的 extern )。
2.臨時全局 local
local 修飾一個變量使其作為一個局部變量在該子程式域内有效,且與my不同,其可以繼續傳遞到該子程式内部調用的其他子程式内,産生一個傳遞的效果。
#!/usr/bin/perl
use 5.010;
# 關鍵字local
sub subroutine0{
my $var = 100; #聲明局部var變量,此時列印将得到局部變量
say $var;
&subroutine1;
}
sub subroutine1{
say $var; #my變量作為私有變量不能傳遞到其調用的子程式内,此時得到全局變量
local $var = 5; #臨時全局變量, 作用域為子程式内部
say $var;
&subroutine2;
}
sub subroutine2{
$var +=1; #local變量将繼續傳遞到其調用的子程式内部
say $var;
}
our $var =1; #全局, 作用域為包
&subroutine0; #輸出100\n 1\n 5\n 6\n
say $var; #輸出1\n
注 1 : local 變量是在運作時起作用,它會将參數的值儲存在一個運作棧中,當執行線程離開所在作用域時,原先作用域暫存的變量會被恢複。
注2 : local和my都隻在一個限定的代碼塊内生效,但是local的變量可以繼續在這個代碼塊中調用的子程式中存在。
3.私有局部my
雖然local操作符的曆史比my操作符久遠,但Perl後來還是新增了my來分擔local的工作,在大部分情況下應首選my,但也有一些特殊情況下必須使用local。
my操作符用于建立詞法作用域變量,通過my建立的變量,存活于聲明開始的地方,直到閉合作用域的結尾。
閉合作用域指的可以是一對花括号中的區域,可以是一個檔案,也可以是一個eval字元串。
#!/usr/bin/perl
use 5.010;
# 關鍵字my
our $var =1; #全局變量,作用域為包
sub subroutine0{
my $var =2; #私有局部變量, 作用域為花括号
$var +=1;
say $var;
&subroutine1;
}
sub subroutine1{
say $var; #my私有變量不能傳遞到其調用的子程式内,仍然讀取到全局變量
}
&subroutine0; #輸出3\n 1\n
say $var; #輸出1\n
注1:my是編譯時在私有符号表中建立新變量,這個變量在運作時無法使用名字進行獨立通路,即它不存在于包符号表中(非全局)。
注 2 :當閉合作用域裡的 my 變量與外層變量重名時,目前 my 變量有效,當退出作用域時,外層變量值不變。
4.持久局部state
使用state操作符來聲明變量,可以在子程式的多次調用期間保留變量之前的值,并将變量的作用域局限于子程式内部。
#!/usr/bin/perl
use 5.010;
# 關鍵字state
sub subroutine0 {
state $var =2; #持久局部變量, 作用域為子程式内部
$var += 1;
say $var;
&subroutine1;
}
sub subroutine1 {
say $var; #由于state變量和my變量都無法傳遞,因而這裡輸出空字元串
}
my $var = 1; #局部變量,作用域目前腳本檔案
&subroutine0; #輸出3\n 空字元串\n
&subroutine0; #輸出4\n 空字元串\n
#這裡輸出4說明state在其作用域内上次操作的值得以儲存
say $var; #輸出1\n
注1:state 修飾的變量在退出子程式後将失效,要了解多次調用期間保留變量之前的值的含義是局限在作用域内的。
注2:state是從Perl 5.10開始引入的,是以使用前必須加上use 5.010或更高版本指令。
注 3 : state 可以聲明标量、數組、哈希。但在聲明數組和哈希時,不能對其初始化(至少 Perl 5.14 不支援)。
3.5 清單和數組
- 清單 指多個值的有序集合, 數組 則相對應是存儲清單的變量
3.5.1 數組
數組指存儲清單的變量,每一個數組都包含一個清單。
基本格式: arrays[0] = 1; $element = arrays[0]; $element = arrays[-1];
- 如何聲明一個數組 $NAME[index] = value
概要
- 數組下标指向一個标量即完成聲明
- 下标為0的元素為數組的第一個元素
- 若聲明的數組下标指向一個大于0的數,則自動擴充其和第一個元素之間的所有元素,擴充的元素預設為undef
#!/usr/bin/perl $arr1[0] = 1; #聲明一個數組arr1,并對其第一個元素指派 $arr1[1.564] = 2; #自動去除小數點 等效于 $arr1[1] = 2; $arr222[99] = 100;#聲明一個數組arr222,并對其第100個元素指派,其餘99個元素值都為undef
- 如何擷取數組的元素 N A M E [ i n d e x ] ∗ ∗ 或 者 ∗ ∗ NAME[index]** 或者 ** NAME[index]∗∗或者∗∗NAME[index的負數]
概要
- $數組下标獲得一個數組元素
- 如果該數組下标不存在,傳回一個undef
- 可以以負數為下标取值,即下标倒數,從-1開始
#!/usr/bin/perl use 5.010; $arr[0] = 'a'; $arr[1] = undef; $arr[2] = "b"; my $value = $arr[0]; #獲得數組的第一個元素 'a' my $value = $arr[999999]; #如果超過數組下标最大長度,不會導緻錯誤,隻是得到一個undef值 my $value = $arr[$#arr];#獲得數組最後一個元素 "b" my $value = $arr[-1]; #獲得數組最後一個元素 "b" my $value = $arr[-2]; #獲得數組倒數第二個元素 undef my $value = $arr[-3]; #獲得數組倒數第三個元素也就是第一個元素 'a' my $value = $arr[-4]; #超過了數組的下标,得到undef值
- 如何擷取數組的長度
概要
- $#ARRAYS_NAME(數組最後一個元素下标) + 1
#!/usr/bin/perl $arr[9] = 10; my $len = $#arr + 1; # $#arr = 9, 9 + 1 等于 10; $arr[$#arr] = 10; # 是以可以通過這種形式修改獲得得到數組的最後一個值,但是要在數組被聲明的前提下,否則将導緻錯誤
3.5.2 清單
清單,清單在程式中表示一列資料。其與數組的關系如同比 值與變量的關系 一樣,一個作為資料,一個作為存儲資料的容器或者說引用。
- 如何表示一個清單?
#!/usr/bin/perl (1, 2, 3) # 包含三個數字元素的清單 (1.25, "str") # 包含兩個元素的清單 ($var1, $var2) # 清單中也可以存儲變量 (1..100) # 清單中可以使用.. 連結數字,其表示包含 1 - 100 的一百個數字 qw(windows linux ubuntu) #quoted world簡寫,等效于('windows', 'linxu', 'ubuntu'), 是快速聲明字元清單的一種簡寫方式,注意其聲明的是單引号的字元,因而不支援字元的轉義 qw|(ios) (andorid) (harmonyOS)| #另外一個qw簡寫寫法,qw簡寫可以使用不同的符号作為分界符,具體原因如該例中的寫法,由于文本本身有括号,再使用括号就無法正确分界。該例等效于('(ios)', '(andorid)', '(harmonyOS)') qw<1 2 3> #qw簡寫中,定界符也可以使用其他明确定義的左右符号,例如{}<>()[]。該例等效于('1','2','3')
- 清單如何指派到變量\數組中?
@數組名 , 将表示整個數組,如下,假設該數組隻有下标 0 - 2 三個元素
for e l e m e n t ( element ( element(arr[0], $arr[1], $arr[2]) {} 等效于 for $element (@arr) {}
#!/usr/bin/perl ($var1, $var2, $var3) = (1, 2, 3, 4, 5); # 清單可以直接指派到變量中,相當于分别給三個變量指派,多餘的元素會被忽略,如果參數不足,則賦予undef值 ($var1, $var2) = ($var2, $var1); # perl中快速交換兩個變量值的方法 ($arr[0],$arr[1],$arr[2]) = qw[獅子 斑鬣狗 花豹 野犬 獵豹 胡狼]; # 給數組下标 0 - 2 的元素指派,多餘的兩個字元會被忽略 @arr = ('獅子', '斑鬣狗', '花豹', '野犬', '獵豹', '胡狼'); # 将清單中的元素指派到數組中,從下标0開始 @arr = qw[獅子 斑鬣狗 花豹 野犬 獵豹 胡狼]; # 将清單中的元素指派到數組中,從下标0開始, 這裡比較上述兩例,可以看到qw簡寫和@符号的使用 @copy = @arr; # 複制一個數組
3.5.3 數組和棧Stack
棧 pop push操作
Perl的數組支援棧Stack 的操作,關于棧結構,可以簡單了解為一個先入後出的清單,其中入的操作稱為push,出的操作稱為pop。
#!/usr/bin/perl
use 5.010;
@arr = 1..10;
say $#arr + 1; # 10
@var = pop(@arr); #出棧操作1
say $#arr + 1; # 9
$val = pop @arr; #出棧操作2
say $#arr + 1; # 8
pop @arr; # 出棧也可以不使用出棧的資料
say $#arr + 1; # 7
push(@arr, 11); #入棧操作1
say $#arr + 1; # 8
push @arr, 12; #入棧操作2
say $#arr + 1; # 9
push @arr, 13..20; #批量的數字入棧
say $#arr + 1; # 17
push @arr, qw[a b c d]; #批量的字元入棧
say $#arr + 1; # 21
@newarr = 'a'..'z';
push @arr, @newarr; #其他數組的資料批量入棧
say $#arr + 1; # 47
for $var (@arr) {
print $var . " ";
}
say;
棧 shift 和 unshift操作
pop和push針對的是數組尾部的元素,而shift和unshift針對的是數組頭部的元素,用法一緻,不多做解釋
#!/usr/bin/perl
@arr = 1..10;
$var = shift @arr;
unshift @arr, 'newElement';
splice 移接操作
基本格式([]表示可選參數): [@RECEIVE_ARR] = splice @ARR_NAME start_index [splice_number] [replace_list]
分别對每一個參數做解釋
- @RECEIVE_ARR 可選的 :splice操作傳回一個數組,即源數組中被移除的部分,@RECEIVE_ARR 用于接收傳回值
- splice 必選的: 操作符本身
- @ARR_NAME 必選的:源數組本身
- start_index 必選的:移除操作開始的下标
- splice_number 可選的:移除的元素個數,預設為 $#ARR_NAME(數組最後一個元素) - start_index + 1;
- replace_list 可選的:在移除操作後,将該清單添加到源數組中,可以是一個其他的數組,或者一個清單直接量
代碼示例如下
#!/usr/bin/perl
use 5.010;
@arr = 'a'..'z'; # a - z 26個字母
@removed = splice @arr, 14; #移除下标14以後的所有元素
say "first removed : @removed"; #輸出第一次移除的元素 o - z
@removed = splice @arr, 0, 7; #移除下标0之後7個元素
say "second removed : @removed"; #輸出第二次移除的元素 a - g
@removed = splice @arr, 0, 7, 1..10; #移除下标0之後7個元素,然後補充1 - 10 10個數字元素
say "the third time removed : @removed"; #輸出第三次移除的元素 h - n 注意第二次移除後元素下标的重新調整
say "current arr : @arr";
3.5.4 字元串的數組内插
數組可以使用@符号直接内插到字元串中,同$變量的内插一樣,但也導緻了@符号的使用限制,需要在實際編寫腳本時注意
例如
#!/usr/bin/perl
use 5.010;
@arr = 1..10;
$str = "countdown: @arr";
say $str;
# email 和數組内插的 符号沖突問題解決
$email = "[email protected]"; #這會被perl認為是内插了一個qq的數組,錯誤的寫法
say $email;
$email = '[email protected]'; #使用單引号限制轉義,正确的寫法
say $email;
$email = "11111\@qq.com"; #手動轉義,比較麻煩,也是正确的寫法
say $email;
3.5.5 數組的常用函數
-
reserver反置數組
基本格式:reverse arraysOrList
- arraysOrList 必選: 要反置的數組或清單直接量
#!/usr/bin/perl my @numbers = 1..10; # 元素為 1 - 10的數組 my @countdownNumbers = reverse @numbers; # 元素為 10 - 1 的數組 my @countdownNumbers2 = reverse 1..10; # 元素為 10 - 1 的數組
-
sort 數組排序
基本格式:sort arraysOrList
- arraysOrList 必選: 要進行排序的數組或清單直接量
根據内部的字元編碼順序對元素進行排序
#!/usr/bin/perl use 5.010; @words = qw [b a g c d f e]; # 亂序字母 @sortedWords1 = sort @words; # 排序後 a b c d e f g @sortedWords2 = sort qw /b a g c d f e/; # 效果與上例相同 say "@words\[email protected]\[email protected]";
-
each 數組周遊
基本格式:($index, $value) = each @array
- $index 必選 : 目前元素下标
- $value 必選 : 目前元素值
- @array 必選 : 周遊的數組
沒次each數組,将傳回一組鍵值對,鍵為數組元素的下标,值為數組元素的值。
實際上,在有了foreach後,each顯得不那麼好用,除非你需要針對數組下标進行一些程式設計,否則使用foreach可能更加友善
each 文法需要 5.012以上版本支援
#!/usr/bin/perl use 5.012; my @fruits = reverse sort qw <banana orange watermelon apple>; # 使用each函數周遊數組 while (my($index, $value) = each @fruits) { say "current element = $index:$value"; } # 使用數組下标foreach周遊數組 foreach my $index (0.. $#fruits) { say "current element = $index:$fruits[$index]"; } # 使用for循環周遊數組 for(my $index = 0; $index <= $#fruits; $index += 1) { say "current element = $index:$fruits[$index]"; }
4 Perl的控制結構
包括以下内容
- 判斷控制結構(if[else], unless[else])
- 循環控制結構 (while, until, forEach, for)
- 循環控制操作符(last next redo)
- 循環體的标簽使用(LABEL)
4.1 判斷結構
4.1.1 If 和 unless
unless 就是反if ,但相較于if,unless不僅在語義上有點反人類,而且缺少elsif多重判斷支援,因而一般使用if即可。
代碼示例
#!/usr/bin/perl
use 5.014;
#使用if判斷
foreach (1..10) {
my $value = (int rand 10); # 生成一個0 - 9 的随機整數
if ($value == 0) { # 當條件為真,進入代碼塊
say "$value";
} elsif($value % 2 == 0) {
say "$value 是個非零偶數";
} else {
say "$value 是個奇數";
}
}
say "-------------分界線-------------";
#使用unless判斷
foreach(1..10) {
my $value = (int rand 10);
unless ($value % 2 == 0) { # 當條件為假,進入代碼塊
say "$value 是個奇數";
} else {
say "$value 是個偶數";
}
}
4.2 循環結構
4.2.1 while 和 until
while 語句中當條件為真時循環執行代碼塊,
until 與之相反,兩者在語義上皆符合人類語言的了解,因而使用哪一種都是可以的。
當條件為真,将持續執行代碼塊, 如下示例将依次列印 2 4 6 8 10 兩遍
#!/usr/bin/perl
$count = 0;
while($count < 10) { #當count小于10時
$count += 2;
print "$count\n";
}
print "-------------分界線-------------\n";
$count = 0;
until($count >= 10) { #直到count>=10
$count += 2;
print "$count\n";
}
4.2.3 foreach 和 for
for和foreach很大程度上能夠混用,這個可以在實際程式設計過程中,選擇自己最喜歡的寫法
針對數組變量或者清單的周遊操作,如下三例都将一次列印 1 - 10
#!/usr/bin/perl
@number = 0;
@numbers = 1..3;
foreach $number (@numbers) {
print "$number\n";
}
for $number (@numbers) {
print "$number\n";
}
for $number (1..3) {
print "$number\n";
}
for (qw[1 2 3]) {
print "$_\n"; #注意這例中沒有控制變量,而是使用 $_ ,這是perl的預設變量。這種寫法也是允許的
}
use 5.010;
for (qw[google apache microsoft]) {
say; #這裡相當于 say "$_";
}
for($int = 0; $int < 5; $int += 1) {
say $int;
}
注:
- 上例中number作為foreach循環的控制變量,在循環開始前是有值的,那麼它将在每一次循環結束後恢複到原來的值 0 。
- 關于$_ $_是perl中的預設變量,在很多單個參數的場景中被使用,包括循環/判斷結構以及各類函數中,具體可以參考https://cn.perlmaven.com/the-default-variable-of-perl,并試試其中的寫法
5 Perl的子程式
perl 也支援類似C的函數功能對程式進行進一步的封裝,子程式的基本格式為
sub 子程式名 {
#這裡書寫子程式的程式主體
}
子程的調用使用 & 符号 或者在程式名後加() 進行調用
&子程式名;
子程式名();
# 帶參數的子程式調用
&子程式名($param1, $param2);
子程式名($param1, $param2);
上述中子程式含參數時,子程式如何擷取這些參數呢?perl并沒有顯式地定義子程式參數地地方。這個時候就可以使用perl的預設參數 $_
#!/usr/bin/perl
use 5.010;
sub mySubroutine {
for $index (0..$#_) { #從0開始到 $_ 參數的最後一個下标
say "參數$index 值為: $_[$index]";
}
# 更直覺一點
say "第一個參數 = $_[0]";
say "第二個參數 = $_[1]";
}
mySubroutine("Hello Subroutine", 2021);
說完程式的參數後,基于我們以往的程式設計經驗,我們很容易聯想到傳回值的問題,程式的傳回值如何定義,如何接收呢?實際上,在子程式執行過程中,最後一次運算的結果将作為子程式的傳回值,程式自動識别而不需要你顯式地使用類似return關鍵字進行傳回,當然了,你也可以直接使用return傳回某個值以結束子程式
代碼示例
#!/usr/bin/perl
use 5.010;
sub mySubroutine0 {
"Hello subroutine";
}
sub mySubroutine1 {
}
sub mySubroutine2 {
return "read paramter" if @_ > 0; #如果參數清單大于0,直接傳回值
"Hello subroutine";
}
$ret0 = mySubroutine0();
$ret1 = mySubroutine1();
$ret2 = mySubroutine2(1); #傳入一個參數
say $ret0; # 輸出 Hello subroutine
say $ret1; # 輸出 空串
say $ret2; # 輸出 read paramter
更多的示例代碼如下所示:
#!/usr/bin/perl
use 5.014;
# 聲明無傳回值的子程式
sub not_ret_func {
# 實際上是有傳回值的,最後一行将print函數将傳回成功執行的代碼1
# 這個傳回值通常作用大多數指令的成功執行标志
# 個别場景下會借以進行條件判斷
print "hello world \n";
}
# 聲明無傳回值的子程式
sub has_ret_func {
# 最後一個值是傳回值
my $test = "return value";
$test;
}
# 調用
my $ret1 = ¬_ret_func;
say 'func1 return = ' . $ret1 . " func2 return = " . &has_ret_func;
# 聲明含參數的子程式
sub has_param_func {
# 預設數組參數$_ 作用子程式的參數清單
$_[0] + $_[1];
}
# 調用含參子程式
my $num1 = 1;
my $num2 = 2;
say $num1 . ' + ' . $num2 . ' = ' . &has_param_func($num1, $num2);
輸出如下
[[email protected] test]# chmod 447 sub.pl
[[email protected] test]# ./sub.pl
hello world
func1 return = 1 func2 return = return value
1 + 2 = 3
[[email protected] test]#
``perl
#!/usr/bin/perl
use 5.010;
sub mySubroutine0 {
“Hello subroutine”;
}
sub mySubroutine1 {
}
sub mySubroutine2 {
return “read paramter” if @_ > 0; #如果參數清單大于0,直接傳回值
“Hello subroutine”;
}
$ret0 = mySubroutine0();
$ret1 = mySubroutine1();
$ret2 = mySubroutine2(1); #傳入一個參數
say $ret0; # 輸出 Hello subroutine
say $ret1; # 輸出 空串
say $ret2; # 輸出 read paramter
[外鍊圖檔轉存中...(img-62W9inoS-1626155603241)]
更多的示例代碼如下所示:
```perl
#!/usr/bin/perl
use 5.014;
# 聲明無傳回值的子程式
sub not_ret_func {
# 實際上是有傳回值的,最後一行将print函數将傳回成功執行的代碼1
# 這個傳回值通常作用大多數指令的成功執行标志
# 個别場景下會借以進行條件判斷
print "hello world \n";
}
# 聲明無傳回值的子程式
sub has_ret_func {
# 最後一個值是傳回值
my $test = "return value";
$test;
}
# 調用
my $ret1 = ¬_ret_func;
say 'func1 return = ' . $ret1 . " func2 return = " . &has_ret_func;
# 聲明含參數的子程式
sub has_param_func {
# 預設數組參數$_ 作用子程式的參數清單
$_[0] + $_[1];
}
# 調用含參子程式
my $num1 = 1;
my $num2 = 2;
say $num1 . ' + ' . $num2 . ' = ' . &has_param_func($num1, $num2);
輸出如下
[[email protected] test]# chmod 447 sub.pl
[[email protected] test]# ./sub.pl
hello world
func1 return = 1 func2 return = return value
1 + 2 = 3
[[email protected] test]#