天天看點

Perl 語言入門學習Perl 語言學習 – 入門篇2 第一個Perl程式3 Perl的資料4 Perl的控制結構5 Perl的子程式

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 進入該操作界面

Perl 語言入門學習Perl 語言學習 – 入門篇2 第一個Perl程式3 Perl的資料4 Perl的控制結構5 Perl的子程式

具體的子產品和安裝指令後續會聊到。

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 語言入門學習Perl 語言學習 – 入門篇2 第一個Perl程式3 Perl的資料4 Perl的控制結構5 Perl的子程式
繼續閱讀的一些補充知識點 -> 給剛接觸腳本語言的同僚
  1. 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 關鍵字的執行階段不同
  2. #!/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";
           
Perl 語言入門學習Perl 語言學習 – 入門篇2 第一個Perl程式3 Perl的資料4 Perl的控制結構5 Perl的子程式

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 字元串的函數操作

  1. 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
               
  2. 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還是等于原文
               
  3. printf 和 sprintf格式化字元串

    基本格式:printf(pattern, $String…)

    • pattern 必選 : 格式化語句,以 % 開頭的字元,每個%号對應一種格式,同時将對一個參數進行格式化
    • $String… 必選 : 要格式化的目标字元,可能有多個,與pattern格式化語句的個數相對應
    基本格式:sprintf(pattern, $String…)

    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  乘法先運作
           
注:
  1. 操作符優先級,參考文檔,常用的如右側所示: () 高于 ++ – 高于 * / % x 高于 + - .
  2. 字元自動轉換數字規則,首字元如果不為數字,則視為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不能聲明一個新的變量,這裡經過實驗是可以,因而删除。此外還添加了部分内容以補充。

知識點概要:

  1. 變量範圍分為兩類:全局、局部
  2. 全局變量标準(our)關鍵字、局部私有變量(my)關鍵字
  3. 局部本地變量(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
           
Perl 語言入門學習Perl 語言學習 – 入門篇2 第一個Perl程式3 Perl的資料4 Perl的控制結構5 Perl的子程式

注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
           
Perl 語言入門學習Perl 語言學習 – 入門篇2 第一個Perl程式3 Perl的資料4 Perl的控制結構5 Perl的子程式

注 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
           
Perl 語言入門學習Perl 語言學習 – 入門篇2 第一個Perl程式3 Perl的資料4 Perl的控制結構5 Perl的子程式

注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
           
Perl 語言入門學習Perl 語言學習 – 入門篇2 第一個Perl程式3 Perl的資料4 Perl的控制結構5 Perl的子程式

注1:state 修飾的變量在退出子程式後将失效,要了解多次調用期間保留變量之前的值的含義是局限在作用域内的。

注2:state是從Perl 5.10開始引入的,是以使用前必須加上use 5.010或更高版本指令。

注 3 : state 可以聲明标量、數組、哈希。但在聲明數組和哈希時,不能對其初始化(至少 Perl 5.14 不支援)。

3.5 清單和數組

  • 清單 指多個值的有序集合, 數組 則相對應是存儲清單的變量
Perl 語言入門學習Perl 語言學習 – 入門篇2 第一個Perl程式3 Perl的資料4 Perl的控制結構5 Perl的子程式

3.5.1 數組

數組指存儲清單的變量,每一個數組都包含一個清單。

基本格式: arrays[0] = 1; $element = arrays[0]; $element = arrays[-1];

  • 如何聲明一個數組 $NAME[index] = value
    概要
    1. 數組下标指向一個标量即完成聲明
    2. 下标為0的元素為數組的第一個元素
    3. 若聲明的數組下标指向一個大于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的負數]
    概要
    1. $數組下标獲得一個數組元素
    2. 如果該數組下标不存在,傳回一個undef
    3. 可以以負數為下标取值,即下标倒數,從-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值
               
  • 如何擷取數組的長度
    概要
    1. $#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;
           
Perl 語言入門學習Perl 語言學習 – 入門篇2 第一個Perl程式3 Perl的資料4 Perl的控制結構5 Perl的子程式

棧 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";
           
Perl 語言入門學習Perl 語言學習 – 入門篇2 第一個Perl程式3 Perl的資料4 Perl的控制結構5 Perl的子程式

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;
           
Perl 語言入門學習Perl 語言學習 – 入門篇2 第一個Perl程式3 Perl的資料4 Perl的控制結構5 Perl的子程式

3.5.5 數組的常用函數

  1. 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 的數組
               
  2. 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]";
               
  3. 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]";
    }
               
Perl 語言入門學習Perl 語言學習 – 入門篇2 第一個Perl程式3 Perl的資料4 Perl的控制結構5 Perl的子程式

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 是個偶數";
    }
}
           
Perl 語言入門學習Perl 語言學習 – 入門篇2 第一個Perl程式3 Perl的資料4 Perl的控制結構5 Perl的子程式

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";
}
           
Perl 語言入門學習Perl 語言學習 – 入門篇2 第一個Perl程式3 Perl的資料4 Perl的控制結構5 Perl的子程式

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;
}
           
Perl 語言入門學習Perl 語言學習 – 入門篇2 第一個Perl程式3 Perl的資料4 Perl的控制結構5 Perl的子程式
注:
  1. 上例中number作為foreach循環的控制變量,在循環開始前是有值的,那麼它将在每一次循環結束後恢複到原來的值 0 。
  2. 關于$_ $_是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);
           
Perl 語言入門學習Perl 語言學習 – 入門篇2 第一個Perl程式3 Perl的資料4 Perl的控制結構5 Perl的子程式

說完程式的參數後,基于我們以往的程式設計經驗,我們很容易聯想到傳回值的問題,程式的傳回值如何定義,如何接收呢?實際上,在子程式執行過程中,最後一次運算的結果将作為子程式的傳回值,程式自動識别而不需要你顯式地使用類似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
           
Perl 語言入門學習Perl 語言學習 – 入門篇2 第一個Perl程式3 Perl的資料4 Perl的控制結構5 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 =  &not_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 =  &not_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]#