FlossDoc: 請協力 GPLv3 的中文翻譯工作。

編寫 Perl 程式

FlossDoc,自由中文開源知識庫

Jump to: navigation, search

如果您已認識其他程式語言 (programming language) 或腳本語言 (scripting language),這是一個非常簡短對 Perl 語法的介紹。

目录

Hello World 程式

以下是一個很簡單的 Perl 程式。

#!/usr/bin/perl

print "Hello, world!"; # 這是注解

資料類別

Perl 和很多腳本語言一樣都屬 lossy type,並不強制分開數字、字串和物體等類型。您可以直接將字串中的數字作運算:

print "5.2" + "1.7";    # + 是數值運算
# 顯示 6.9
print "5.2" . "1.7";    # . 是字串運算
# 顯示 5.21.7


基本而言,Perl 的變數只分三類:

  • 純量 (scalar) - 名稱以錢號 ($) 開頭,表示任何單一資料。例如: $num = 6.9; $string = "Hello World!!";
  • 陣列 (array) - 名稱以 @ 開頭,表示包括多個純量的串列。例如: @odds = (1, 3, 5, 7, 9);
  • 散列 (hash, associate array) - 名稱以百分比號 (%) 開頭,

同樣,Perl 中的變數和很多 scripting 語言一樣無需要預先宣告 (declaration)。但如果開程式開啟加上 use strict; 敘述,可以令 Perl 要求每一個變數都要變 my $a, $b; 預先宣告,減少拼錯變數名稱的機會。

詳情可以參見 perldata(1)[1]

純量 ($scalar)

純量是 Perl 可以處理最簡單的類型,表示任何單一資料,包括數值 (numeric)、字串 (string) 和參考 (reference)。例如:

  • 整數 (integer): 1, 20, -280, 031 (八進位數,相等於 25), 0xA31E (十六進位數,相等於 41758) 和 0b101101 (二進位數,相等於 45)
  • 浮點數 (float): 3.141573259, 1.7E10, -2.56e1510.0
  • 字串 (string): '哈囉! 世界!', '12345678', "My name is $myname\n"

純量變數以錢號 ($) 開頭。

陣列 (@array)

陣列或串列 (list) 為一連純量組成 (0 個元素或以上) 組成的資料類型,例如:

(1, 2, 3)                          # 三個元素的串列
('John', "Mary", 2, 4, 'Peter')    # 五個元素的串列
()                                 # 空串列 (0 個元素的串列)

陣列變數以 @ 為開頭,可以使用 $var[$i] 存取第 $i - 1 個元表的值:

@names = ('John', 'Mary', 'Peter');
print $names[1];                   # 顯示 Mary
$names[2] = 'David';               # @names 變成 ('John', 'Mary', 'David')
@nums = (2, 1, 6, 17);
@list = (@names, @nums);           # @list 變成 ('John', 'Mary', 'David', 2, 1, 6, 17)
@words = qw(apple boy cat door);   # @words 變成 ('apple', 'boy', 'cat', 'door')
print $#words;                     # 顯示 4 (@words 的元素數目)

foreach $word ( @words ) {
    print "$word\n";
}

print pop(@words);            # 顯示 'door', @words 變成 ('apple', 'boy', 'cat')
push(@words, 'ear');          # @words 變成 ('apple', 'boy', 'cat', 'ear')
print shift(@words);          # 顯示 'apple', @words 變成 ('boy', 'cat', 'ear')
unshift(@words, 'zebra');     # @words 變成 ('zebra', 'boy', 'cat', 'ear')

注意事項:

  • 取用陣列其中一個元素為純量,所以 $ 開頭。取用整個陣列則以 @ 開頭。
  • 陣列變數和純量變數可以使用相同的名稱,但表示兩個獨立的變數。例如 $x 和 @x 是不同的變數。

散列 (%hash)

散列 (hash) 或叫作 associated arrays,和陣列很相似,但陣列用整數作索引,而散列則用字串作索引,稱為鍵 (key),對應的內容為值 (value)。散列變數以百分比號 (%) 作開頭,可以用 $var{$i} 存取鍵為 $i 的值:

%scores = {
    'John Smith' => 88.2,
    'Mary Doe' => 92.5,
    'David' => 45.12
};

print $scores{'David'};      # 顯示 45.12
$scores{'peter'} = 'unknown';
print $scores{peter};        # 鍵的單引號可以省略

print "David has score\n" if exists $scores{'David'};

@names = keys(%scores);      # @names 變成 ('John Smith', 'Mary Doe', 'David', 'peter')
@scores = values(%scores);   # @scores 變成 (88.2, 92.5, 45.12, 'unknown')

while (($key, $value) = each %scores) {
    print "$key => $value\n";
}

注意事項:

  • 和陣列同理,取用散列其中一個鍵的值為純量,所以 $ 一樣以開頭。取用整個散列則以 % 開頭。
  • 散列變數,陣列變數和純量變數可以使用相同的名稱,但表示三個獨立的變數。例如 $x,@x 和 %x 是三個不同的變數。

內建變數

以下只是列出幾個常用的內建變數,完整的列表請參看 perlvar(1)[2]

  • $_ - 預設參數。任何函數沒有提供參數時會自動使用此變數作為函數,例如 print; 等於 print $_;,而 /HKD\d+\.\d{2}/ 等於 $_ =~ /HKD\d+\.\d{2}/
  • $0 - 現時執行程式的檔案路徑 (包括程式名稱)
  • @ARGV - 現時執行程式的命令列參數
  • @_ - 現時執行子程序的參數
  • $$ - 現時執行程式的進程識別號 (PID)
  • $. - 最後存取檔案標頭 (file handle) 的現時行號。

運算

值的真假:

  • 0 為假,其他數值皆為真。
  • '0', "0" 和空字串 、"" 為假,其他字串皆為真。
  • 運算結果可以轉為 "0" 者為假,其餘皆為真。
  • 未定義 undef 為假,有定意為真。
運算元 解析 例子
-> 呼叫方法/解參考
$a{'name'} = 'John Smith';
$obj = \$a;
print $obj->{'name'};
++ 遞增
$i = 10
$i++; # 相等於 $i = $i + 1; $i 的值變成 11
print $i++ + 4; # 顯示 15,  $i 的值變成 12
print ++$i + 4; # 顯示 18,  $i 的值變成 13
-- 遞減
$i = 20
$i--; # 相等於 $i = $i - 1; $i 的值變成 19
print $i-- + 4; # 顯示 23,  $i 的值變成 18
print --$i + 4; # 顯示 21,  $i 的值變成 17
** 乘幕 print 2 ** 5; # 顯示 32
 !  ! ($x == 0) # 相等於 $x != 0
~ 位元運算非 printf "%b\n", ~ 0b11010011; # 顯示 11111111111111111111111100101100
\ 參考
=~ 比對 $str =~ /match/
 !~ 非比對 $str !~ /nothing/
* 4.2 * 12.7 # 結果為 53.34
/ 24 / 9 # 結果為 2
% 餘數 123 % 12 # 結果為 3
x 重複字串 print '+-' x 4; # 顯示 '+-+-+-+-'
+ 4 + 17 # 結果為 21
- 123.4 - 76.5 # 結果為 46.9
. 連接字串 print 'John ' . 'Smith'; # 顯示 'John Smith'
<< 位元左移 0b1011 << 2 # 結果為 0b101100
>> 位元右移 0b1011 >> 1 # 結果為 0b101
< 小於
> 大於
<= 小於或等於
>= 大於或等於
lt 字串小於
gt 字串大於
le 字串小於或等於
ge 字串大於或等於
== 等於
 != 不等於
<=> 數值比較
eq 字串等於
ne 字串不等於
comp 字串比較
& 位元 AND
| 位元 OR
^ 位元 XOR
&&
||
.. 範圍 2 .. 7 # 相等於 (2, 3, 4, 5, 6, 7)
 ? : 三元運算 ($a > $b) ? $a : $b
= 指定
+= 增加 $n += $x # 相等於 $n = $n + $x
-= 減小 $n -= $x # 相等於 $n = $n - $x
*= 乘上 $n *= $x # 相等於 $n = $n * $x
,
=>
not 邏輯 NOT
and 邏輯 AND
or 邏輯 OR
xor 邏輯 XOR

基本語法

每一個敘述 (statement) 一定以冒號 (;) 結束。

詳情可以參見 perlsyn(1)[3]

如果..則 (if..then)

最簡單的形式為:

if (算式) { 敘述... }

當然可以加上否則 (else) 的情況:

if (算式) { 敘述... } else { 敘述... }

否則如果 (else if) 則用 elsif:

if (算式) { 敘述... } elsif (算式) { 敘述... }...  else { 敘述... }

還有 Perl 獨有的單行式:

敘述 if 算式;

別忘了 Perl 還有 unless 敘述,相等於 if (! 算式) ...:

unless (算式) { 敘述... } else { 敘述... }

或:

敘述 unless 算式;

例如:

if (!open(FOO)) {
   die "Can't open $FOO: $!";
}
print "Basset hounds got long ears" if length $ear >= 10;
go_outside() and play() unless $is_raining;

open(FOO) or die "Can't open $FOO: $!";     # FOO or bust!
open(FOO) ? 'hi mom' : die "Can't open $FOO: $!";
# a bit exotic, that last one

注意事項:

  • 是 elsif,不是 elseif,中間沒有 e 的。

while..do

while (算式) { 敘述... }

可以加上 continue 區塊 (每次完成 loop 都會執行 continue 區塊的敘述,包括 next 後):

while (算式) { 敘述... } continue { 敘述... }

單行式:

敘述 while 算式;

Perl 獨有的 until 等於 while (! 算式):

until (算式) { 敘述... }

或:

敘述 until 算式;

例如:

while (($key, $value) = each %hash) {
    print "$key = $value\n";
}
$i = $j = 0;
print $i++ while $i <= 10;
print $j++ until $j >  10;

$i = 0;
while ($i < 10) {
    print "$i\n";
} continue {
    $i++;
}
# 以上相等於 for ($i = 0; $i < 10; $i++) { print "$i\n"; }

do..while

do { 敘述... } while 算式;
do { 敘述... } until 算式;
do {
    $line = <STDIN>;
    ...
} until $line  eq ".\n";

例如:

do {
    $i++;
    print "$i\n";
} while ( $i < 100 );

for loop

C 語言的 for 形式:

for (算式; 算式; 算式) { 敘述... }

亦有方便走訪所有陣列元素的 foreach 形式

foreach 變數 ( 陣列 ) { 敘述... }

或:

敘述 foreach 陣列;
for ($i = 1; $i < 10; $i++) {
    ...
}

print "Hello $_!\n" foreach qw(world Dolly nurse);

loop 控制

  • last - 跳出 loop
  • next - 跳至下一次 loop 或 continue 區塊
  • redo - 重新執行這一次 loop

常用函數 (function)

這裡只列出較常用的內建函數 (function),完整列表可以參見 perlfunc(1)[4]

如果使用時沒有提無參數,一般預設使用變數 $_。


輸出相關:

函數 描述 例子
print $STRINGS,... 顯示文字
print "Hello, world\n";
print "This ", "is ", "my ", "first ", "program!\n";
print('Now is: ', localtime, "\n");
printf $FORMAT, $ARGS,... 格式化顯示資料
printf "Name: %s\nAge: %d\n", $name, $age;
printf("The cost is HKD%8.2f\n", $cost);

檔案/目錄相關:

函數 描述 例子
-e $FILE 檔案是否存在 print "file exists\n" if -e 'file';
-z $FILE 檔案大小是零 (空檔案) print "file is empty\n" if -z 'file';
-s $FILE 檔案大小不是零 print "file is not empty\n" if -s 'file';
-f $FILE 檔案為一般檔案 (plain file) print "file is plain file\n" if -f 'file';
-d $FILE 檔案為目錄 (directory) print "file is directory\n" if -d 'file';
-l $FILE 檔案為符號連結 (symbolic link) print "file is symlink\n" if -l 'file';
-p $FILE 檔案為 named pipe (FIFO) print "file is named pip\n" if -p 'file';
-S $FILE 檔案為目錄 (directory) print "file is socket\n" if -S 'file';
-b $FILE 檔案為區塊裝置 (block special file) print "file is block device\n" if -b 'file';
-c $FILE 檔案為字元裝置 (character special file) print "file is character device\n" if -c 'file';
-t $FILE filehandle 是指向 tty print "standard input is tty" if -t STDIN;
-r $FILE 是否為可以被有效 uid/gid 讀取的檔案 print "readme is readable\n" if -r 'readme';
-w $FILE 是否為可以被有效 uid/gid 寫入的檔案 print "editme is writable\n" if -w 'editme';
-x $FILE 是否為可以被有效 uid/gid 執行的檔案 print "runme is executable\n" if -x 'runme';
-o $FILE 是否為可以為有效 uid 所擁有 print "file is mine\n" if -o 'file';
-R $FILE 是否為可以被直正 uid/gid 讀取的檔案 print "readme is readable\n" if -R 'readme';
-W $FILE 是否為可以被直正 uid/gid 寫入的檔案 print "editme is writable\n" if -W 'editme';
-X $FILE 是否為可以被直正 uid/gid 執行的檔案 print "runme is executable\n" if -X 'runme';
-O $FILE 是否為可以為直正 uid 所擁有 print "file is mine\n" if -O 'file';
-u $FILE 檔案有設定 setuid print "file has suid set\n" if -u 'file';
-g $FILE 檔案有設定 setgid print "file has sgid set\n" if -g 'file';
-k $FILE 檔案有設定 sticky bit print "file has sticky bit set\n" if -k 'file';
chdir $DIR 改變工作目錄 chdir('/var/tmp');
chmod $MODE, $FILES,... 改變檔案權根 chmod(0755, 'bin');
chown $UID, $GID, $FILES,... 改變檔案擁有者和所屬群組。$UID/$GID 為 -1 一般表示不改變該值 chown(1001, 1001, @filenames);

檔案存取相關:

函數 描述 例子
close FILEHANDLE 關閉檔案

字串處理:

函數 描述 例子
chomp $STR 切斷字串尾部的檔案紀錄分隔符 (記錄在 $/,一般為 "\n"),傳回值為切斷的字元數目。
while ( <> ) {
   chomp;                 # 刪除尾部的新行字元 ("\n")
   @fields = split(/:/);
}
chr $NUM 傳回 ASCII/UNICODE 為 $NUM 的字元 chr(65) # 即 'A'

自訂函數

sub force() {
    my ($mass, $acceleration) = @_;
    return $mass * $acceleration; 
}

print "Force = %f\n", 5.0, 10;

參考資料

  1. GNU/Linux Manpage: perldata(1) - Perl data typesLinux.pngUbuntu.pngDebian.png[SuSE][OpenSuSE] URL: http://search.cpan.org/dist/perl/pod/perldata.pod
  2. GNU/Linux Manpage: perlvar(1) - Perl predefined variablesLinux.pngUbuntu.pngDebian.png[SuSE][OpenSuSE] URL: http://search.cpan.org/dist/perl/pod/perlvar.pod
  3. GNU/Linux Manpage: perldata(1) - Perl syntaxLinux.pngUbuntu.pngDebian.png[SuSE][OpenSuSE] URL: http://search.cpan.org/dist/perl/pod/perlsyn.pod
  4. GNU/Linux Manpage: perldata(1) - Perl syntaxLinux.pngUbuntu.pngDebian.png[SuSE][OpenSuSE] URL: http://search.cpan.org/dist/perl/pod/perlfunc.pod

請參看

外部資料

Personal tools