perlintro - Perl 簡介和概述
本文件旨在讓您快速了解 Perl 程式語言,並提供進一步文件的指標。它旨在作為那些不熟悉該語言的人的「引導」指南,並提供足夠的資訊,讓您能夠閱讀其他人的 Perl 並大致了解其作用,或撰寫您自己的簡單腳本。
此簡介文件並非旨在完整無缺。甚至也非旨在完全準確無誤。在某些情況下,為了傳達一般概念而犧牲了完美性。強烈建議您閱讀完本簡介後,再參閱 Perl 完整手冊中的更多資訊,其目錄可見於 perltoc。
在整份文件中,您會看到對 Perl 文件其他部分的參考。您可以使用 perldoc
指令或您用來閱讀本文件的任何方法來閱讀該文件。
在 Perl 的文件中,您會發現許多範例,旨在協助說明所討論的功能。請記住,其中許多範例是程式碼片段,而非完整的程式。
這些範例通常反映文件該部分作者的風格和偏好,且可能比實際程式中對應的程式碼行簡短。除非另有註明,否則您應假設 use strict
和 use warnings
陳述出現在「程式」的前面,且已宣告使用任何變數,即使已省略這些宣告以使範例更易於閱讀。
請注意,這些範例是由許多不同的作者在數十年的時間內撰寫的。因此,風格和技巧會有所不同,儘管已盡力使同一部分中的風格差異不要太大。不要認為一種風格比其他風格好 - 「有許多種方法可以完成」是 Perl 的座右銘之一。畢竟,在您作為程式設計師的旅程中,您可能會遇到不同的風格。
Perl 是一種通用程式設計語言,最初是為文字處理而開發,現在用於範圍廣泛的任務,包括系統管理、網頁開發、網路程式設計、GUI 開發等。
此語言旨在實用(易於使用、高效、完整),而非美觀(小巧、優雅、簡約)。其主要特色在於易於使用、同時支援程序導向和物件導向 (OO) 程式設計、內建強大的文字處理支援,以及擁有全球最令人印象深刻的第三方模組集合。
Perl 的不同定義載於 perl、perlfaq1,以及其他地方。從中我們可以確定,Perl 對不同的人來說是不同的東西,但許多人認為它至少值得寫出來。
從 Unix 命令列執行 Perl 程式
perl progname.pl
或者,將此內容置於指令碼的第一行
#!/usr/bin/env perl
... 並將指令碼執行為 /path/to/script.pl。當然,它需要先具有可執行權限,因此請執行 chmod 755 script.pl
(在 Unix 中)。
(此起始行假設您有 env 程式。您也可以直接輸入 Perl 可執行檔的路徑,例如 #!/usr/bin/perl
)。
如需更多資訊,包括 Windows 等其他平台的說明,請閱讀 perlrun。
Perl 預設上非常寬容。為了讓它更強健,建議每個程式都以以下幾行開始
#!/usr/bin/perl
use strict;
use warnings;
這兩行額外要求 Perl 偵測程式碼中的各種常見問題。它們檢查不同的內容,因此您需要同時使用。use strict;
偵測到的潛在問題會導致您的程式在遇到時立即停止,而 use warnings;
只會發出警告(例如命令列開關 -w),並讓您的程式繼續執行。如需進一步了解它們,請查看它們在 strict 和 warnings 中各自的手冊頁面。
use v5.35
(或更高版本)宣告將啟用 strict
和 warnings
#!/usr/bin/perl
use v5.35;
除了啟用 strict
和 warnings
實用程式外,此宣告還會啟動 "功能套件";一個命名功能的集合,可啟用許多較新的語言新增功能和變更,偶爾也會移除發現設計錯誤並建議不使用的舊功能。
Perl 指令碼或程式包含一個或多個陳述式。這些陳述式只會以直接的方式寫在指令碼中。不需要有 main()
函式或類似內容。
Perl 陳述式以分號結尾
print "Hello, world";
註解以井號符號開頭,並執行至行尾
# This is a comment
空白字元無關緊要
print
"Hello, world"
;
...引號字串內除外
# this would print with a linebreak in the middle
print "Hello
world";
文字字串可用雙引號或單引號標示
print "Hello, world";
print 'Hello, world';
不過,只有雙引號會「插入」變數和特殊字元,例如換行符號 (\n
)
print "Hello, $name\n"; # works fine
print 'Hello, $name\n'; # prints $name\n literally
數字不需要引號標示
print 42;
你可以使用括號表示函數引數,或依個人喜好省略括號。只有在偶爾需要釐清優先順序時才需要括號。
print("Hello, world\n");
print "Hello, world\n";
可以在 perlsyn 找到有關 Perl 語法更詳細的資訊。
Perl 有三種主要的變數類型:純量、陣列和雜湊。
純量表示單一值
my $animal = "camel";
my $answer = 42;
純量值可以是字串、整數或浮點數,而 Perl 會在需要時自動在這些值之間轉換。你必須在第一次使用時使用 my
關鍵字宣告這些值。(這是 use strict;
的其中一項需求。)
純量值可以用各種方式使用
print $animal;
print "The animal is $animal\n";
print "The square of $answer is ", $answer * $answer, "\n";
Perl 定義了許多具有簡短名稱的特殊純量,通常是單一標點符號或數字。這些變數用於各種用途,並在 perlvar 中有說明。目前你只需要知道「預設變數」$_
。它用作 Perl 中許多函數的預設引數,而且會由某些迴圈結構隱含設定。
print; # prints contents of $_ by default
陣列表示值清單
my @animals = ("camel", "llama", "owl");
my @numbers = (23, 42, 69);
my @mixed = ("camel", 42, 1.23);
陣列從 0 開始編號。以下是取得陣列中元素的方式
print $animals[0]; # prints "camel"
print $animals[1]; # prints "llama"
特殊變數 $#array
會告訴你陣列中最後一個元素的索引
print $mixed[$#mixed]; # last element, prints 1.23
你可能會想使用 $#array + 1
來告訴你陣列中有多少個項目。不用這麼麻煩。事實上,在 Perl 預期找到純量值(「純量內容」)的地方使用 @array
會給你陣列中的元素數量
if (@animals < 5) { ... }
我們從陣列取得的元素以 $
開頭,因為我們只從陣列中取得單一值;你要求一個純量,你就會得到一個純量。
從陣列取得多個值
@animals[0,1]; # gives ("camel", "llama");
@animals[0..2]; # gives ("camel", "llama", "owl");
@animals[1..$#animals]; # gives all except the first element
這稱為「陣列切片」。
你可以對清單執行各種有用的動作
my @sorted = sort @animals;
my @backwards = reverse @numbers;
也有幾個特殊的陣列,例如 @ARGV
(你的指令碼的命令列引數)和 @_
(傳遞給子常式的引數)。這些在 perlvar 中有說明。
雜湊表示一組鍵/值對
my %fruit_color = ("apple", "red", "banana", "yellow");
你可以使用空白字元和 =>
算子更漂亮地排列它們
my %fruit_color = (
apple => "red",
banana => "yellow",
);
取得雜湊元素
$fruit_color{"apple"}; # gives "red"
你可以使用 keys()
和 values()
取得鍵和值的清單。
my @fruits = keys %fruit_color;
my @colors = values %fruit_color;
雜湊沒有特定的內部順序,不過你可以對鍵進行排序並逐一迴圈處理。
就像特殊的純量和陣列一樣,也有特殊的雜湊。其中最有名的是 %ENV
,它包含環境變數。在 perlvar 中閱讀有關它的所有資訊(以及其他特殊變數)。
純量、陣列和雜湊在 perldata 中有更完整的說明。
可以使用參考來建構更複雜的資料類型,這允許你在清單和雜湊中建構清單和雜湊。
參照是一個純量值,可以參照任何其他 Perl 資料類型。因此,透過將參照儲存為陣列或雜湊元素的值,您可以輕鬆在陣列和雜湊中建立清單和雜湊。下列範例顯示使用匿名雜湊參照的兩層雜湊雜湊結構。
my $variables = {
scalar => {
description => "single item",
sigil => '$',
},
array => {
description => "ordered list of items",
sigil => '@',
},
hash => {
description => "key/value pairs",
sigil => '%',
},
};
print "Scalars begin with a $variables->{'scalar'}->{'sigil'}\n";
可以在 perlreftut、perllol、perlref 和 perldsc 找到關於參照主題的詳盡資訊。
在上一節中,所有範例都使用語法
my $var = "value";
實際上不需要 my
;您可以只使用
$var = "value";
但是,上述用法會在整個程式中建立全域變數,這是糟糕的程式設計慣例。my
會建立詞彙範圍變數。變數的範圍限定在定義它們的區塊中(也就是由大括號包圍的一串陳述式)。
my $x = "foo";
my $some_condition = 1;
if ($some_condition) {
my $y = "bar";
print $x; # prints "foo"
print $y; # prints "bar"
}
print $x; # prints "foo"
print $y; # prints nothing; $y has fallen out of scope
在 Perl 指令碼最上方結合使用 my
和 use strict;
表示直譯器會挑出某些常見的程式設計錯誤。例如,在上述範例中,最後的 print $y
會導致編譯時間錯誤,並阻止您執行程式。強烈建議使用 strict
。
Perl 具有大部分常見的條件和迴圈建構。
條件可以是任何 Perl 表達式。請參閱下一節中的運算子清單,以取得關於比較和布林邏輯運算子的資訊,這些運算子通常用於條件式陳述式中。
if ( condition ) {
...
} elsif ( other condition ) {
...
} else {
...
}
它也有否定版本
unless ( condition ) {
...
}
這是提供給 if (!condition)
的更易讀版本。
請注意,即使區塊中只有一行,Perl 中也需要大括號。但是,有一個聰明的方法可以讓您的單行條件區塊更像英文
# the traditional way
if ($zippy) {
print "Yow!";
}
# the Perlish post-condition way
print "Yow!" if $zippy;
print "We have no bananas" unless $bananas;
while ( condition ) {
...
}
也有否定版本,原因與我們有 unless
相同
until ( condition ) {
...
}
您也可以在後置條件中使用 while
print "LA LA LA\n" while 1; # loops forever
與 C 完全相同
for ($i = 0; $i <= $max; $i++) {
...
}
Perl 中很少需要 C 風格的 for 迴圈,因為 Perl 提供了更友善的清單掃描 foreach
迴圈。
foreach (@array) {
print "This element is $_\n";
}
print $list[$_] foreach 0 .. $max;
# you don't have to use the default $_ either...
foreach my $key (keys %hash) {
print "The value of $key is $hash{$key}\n";
}
foreach
關鍵字實際上是 for
關鍵字的同義字。請參閱 "Foreach Loops" in perlsyn
。
有關迴圈建構(以及本概述中未提及的一些建構)的更多詳細資訊,請參閱 perlsyn。
Perl 附帶各種內建函式。我們已經看過的一些函式包括 print
、sort
和 reverse
。它們的清單載於 perlfunc 的開頭,您可以使用 perldoc -f functionname
輕鬆閱讀任何給定的函式。
Perl 運算子在 perlop 中有完整的說明,但以下是一些最常見的運算子
+ addition
- subtraction
* multiplication
/ division
== equality
!= inequality
< less than
> greater than
<= less than or equal
>= greater than or equal
eq equality
ne inequality
lt less than
gt greater than
le less than or equal
ge greater than or equal
(為何我們有獨立的數字和字串比較?因為我們沒有特殊變數類型,而 Perl 需要知道是否以數字方式排序(其中 99 小於 100)或以字母順序排序(其中 100 出現在 99 之前)。
&& and
|| or
! not
(and
、or
和 not
不僅在上述表格中作為運算子的描述。它們本身也受支援作為運算子。它們比 C 式運算子更具可讀性,但優先權與 &&
及其相關運算子不同。請查看 perlop 以取得更多詳細資料。)
= assignment
. string concatenation
x string multiplication (repeats strings)
.. range operator (creates a list of numbers or strings)
許多運算子可以與 =
結合,如下所示
$a += 1; # same as $a = $a + 1
$a -= 1; # same as $a = $a - 1
$a .= "\n"; # same as $a = $a . "\n";
您可以使用 open()
函數開啟檔案以進行輸入或輸出。它在 perlfunc 和 perlopentut 中有詳細的說明,但簡而言之
open(my $in, "<", "input.txt") or die "Can't open input.txt: $!";
open(my $out, ">", "output.txt") or die "Can't open output.txt: $!";
open(my $log, ">>", "my.log") or die "Can't open my.log: $!";
您可以使用 <>
運算子從開啟的檔案處理程式讀取資料。在純量內容中,它會從檔案處理程式讀取單一行,而在清單內容中,它會讀取整個檔案,並將每一行指定給清單的元素
my $line = <$in>;
my @lines = <$in>;
一次讀取整個檔案稱為 slurping。它可能很有用,但可能會耗用記憶體。大多數文字檔處理都可以使用 Perl 的迴圈結構一次處理一行。
<>
運算子最常出現在 while
迴圈中
while (<$in>) { # assigns each line in turn to $_
print "Just read in this line: $_";
}
我們已經看過如何使用 print()
輸出到標準輸出。不過,print()
也可以採用一個選擇性的第一個引數,指定要輸出的檔案處理程式
print STDERR "This is your final warning.\n";
print $out $record;
print $log $logmessage;
當您完成檔案處理程式時,您應該 close()
它們(不過老實說,如果您忘記了,Perl 會自行清理)。
close $in or die "$in: $!";
Perl 的正規表示式支援既廣泛又深入,在 perlrequick、perlretut 和其他地方都有冗長的說明文件。不過,簡而言之
if (/foo/) { ... } # true if $_ contains "foo"
if ($a =~ /foo/) { ... } # true if $a contains "foo"
//
比對運算子在 perlop 中有說明。它預設作用於 $_
,或可以使用 =~
繫結運算子(也在 perlop 中有說明)繫結到其他變數。
s/foo/bar/; # replaces foo with bar in $_
$a =~ s/foo/bar/; # replaces foo with bar in $a
$a =~ s/foo/bar/g; # replaces ALL INSTANCES of foo with bar
# in $a
s///
替換運算子在 perlop 中有說明。
您不只能比對固定字串。事實上,您可以使用更複雜的正規表示式,比對您能想到的幾乎所有東西。這些在 perlre 中有很詳細的說明,但在此同時,這裡有一個快速秘笈
. a single character
\s a whitespace character (space, tab, newline,
...)
\S non-whitespace character
\d a digit (0-9)
\D a non-digit
\w a word character (a-z, A-Z, 0-9, _)
\W a non-word character
[aeiou] matches a single character in the given set
[^aeiou] matches a single character outside the given
set
(foo|bar|baz) matches any of the alternatives specified
^ start of string
$ end of string
量詞可用於指定您想要比對的先前項目的數量,其中「項目」表示字面字元、上面列出的其中一個元字元,或括號中的字元或元字元群組。
* zero or more of the previous thing
+ one or more of the previous thing
? zero or one of the previous thing
{3} matches exactly 3 of the previous thing
{3,6} matches between 3 and 6 of the previous thing
{3,} matches 3 or more of the previous thing
一些簡短範例
/^\d+/ string starts with one or more digits
/^$/ nothing in the string (start and end are
adjacent)
/(\d\s){3}/ three digits, each followed by a whitespace
character (eg "3 4 5 ")
/(a.)+/ matches a string in which every odd-numbered
letter is a (eg "abacadaf")
# This loop reads from STDIN, and prints non-blank lines:
while (<>) {
next if /^$/;
print;
}
除了群組之外,括號還有第二個用途。它們可用於擷取正規表示式比對部分的結果,以便稍後使用。結果會出現在 $1
、$2
等變數中。
# a cheap and nasty way to break an email address up into parts
if ($email =~ /([^@]+)@(.+)/) {
print "Username is $1\n";
print "Hostname is $2\n";
}
Perl 正規表示式也支援反向參照、先行斷言,以及各種其他複雜的細節。在 perlrequick、perlretut 和 perlre 中閱讀所有相關資訊。
撰寫子常式很簡單
sub logger {
my $logmessage = shift;
open my $logfile, ">>", "my.log" or die "Could not open my.log: $!";
print $logfile $logmessage;
}
現在我們可以使用子常式,就像任何其他內建函式一樣
logger("We have a logger subroutine!");
那個 shift
是什麼?嗯,子常式的引數可透過稱為 @_
的特殊陣列提供給我們(有關這方面的更多資訊,請參閱 perlvar)。shift
函式的預設引數剛好是 @_
。因此,my $logmessage = shift;
會將引數清單中的第一個項目移出,並將其指定給 $logmessage
。
我們也可以用其他方式操作 @_
my ($logmessage, $priority) = @_; # common
my $logmessage = $_[0]; # uncommon, and ugly
子常式也可以傳回值
sub square {
my $num = shift;
my $result = $num * $num;
return $result;
}
然後像這樣使用它
$sq = square(8);
有關撰寫子常式的更多資訊,請參閱 perlsub。
物件導向 Perl 相對簡單,並使用參照來實作,這些參照知道它們是哪種類型的物件,這是基於 Perl 的套件概念。但是,物件導向 Perl 在很大程度上超出了本文檔的範圍。請閱讀 perlootut 和 perlobj。
作為一個初學者 Perl 程式設計師,您最常使用物件導向 Perl 的方式是使用第三方模組,這些模組在下面有說明。
Perl 模組提供一系列功能,可協助您避免重複造輪子,且可從 CPAN ( http://www.cpan.org/ ) 下載。Perl 散布本身包含許多熱門模組。
模組的類別範圍從文字處理到網路通訊協定,再到資料庫整合與圖形。CPAN 也提供模組的分類清單。
若要了解如何安裝從 CPAN 下載的模組,請閱讀 perlmodinstall。
若要了解如何使用特定模組,請使用 perldoc Module::Name
。您通常會想要 use Module::Name
,接著便能存取模組的匯出函式或 OO 介面。
perlfaq 包含與許多常見任務相關的問題與解答,並經常提供建議,說明可使用哪些好用的 CPAN 模組。
perlmod 說明 Perl 模組的概況。 perlmodlib 列出隨 Perl 安裝附帶的模組。
如果您有撰寫 Perl 模組的衝動,perlnewmod 將會提供您良好的建議。
Kirrily "Skud" Robert <skud@cpan.org>