Perl的基本語法 |
前言:
這篇文章是花了我很多時(shí)間、費(fèi)了我很多心血才完成的,雖然連我自己都覺得無法達(dá)到盡善盡美的境界,但希望能幫助大家入門,稍微了解到Perl到底是個(gè)什麼樣的東西,Perl到底有那些強(qiáng)大的功能,那麼這篇文章的目的就達(dá)到了。我分做資料型態(tài)、控制敘述、副程式、I/O和檔案處理、Regular
Expressions、Spectial
Variables、Help
這幾部分來講解,但只是敘述了一些Perl的基本語法而已,Perl活潑的特性和程式的技巧就無法一一詳述了,甚為缺憾。
(1) 資料型態(tài)(Data
type):
Perl的資料型態(tài)大致分為四種:Scalar、Scalar Array、Hash Array、References,看起來雖少但用起來卻綽綽有余。尤其在寫Perl程式時(shí)可以不必事先宣告變數(shù),這一點(diǎn)對剛學(xué)程式語言的人甚為方便,不過為了以後程式除錯(cuò)和維護(hù)方便,我建議你還是養(yǎng)成事先宣告變數(shù)的習(xí)慣比較好。
純量變數(shù)是Perl里最基本的一種資料型態(tài),它可以代表一個(gè)字元、字串、整數(shù)、甚至浮點(diǎn)數(shù),而Perl把它們都看成是一樣的東東!
你甚至可以混著用,不可思議吧。例如: 純量陣列,陣列內(nèi)的每一個(gè)元素都是Scalar variable。宣告及使用方式如下: 雜湊陣列也叫做相關(guān)陣列,它和一般陣列沒什麼不同,差別只是在它的索引值用的是字串,而非一般陣列所用的整數(shù)值,因此相關(guān)陣列不像一般陣列一樣有次序的概念,它沒有所謂的第一項(xiàng)資料這種說法。它就相當(dāng)於把一堆變數(shù)組合成一個(gè)group,然後我們可以透過索引字串存取這個(gè)group每一個(gè)元素的值。相關(guān)陣列的宣告及使用方式如下:
Perl有上述三個(gè)函數(shù)可對相關(guān)陣列做運(yùn)算:keys函數(shù)可取出相關(guān)變數(shù)的索引值,組成一純量陣列,注意這些由keys函數(shù)取出的索引值沒有次序性;values函數(shù)可取出相關(guān)變數(shù)的元素值;each函數(shù)則會(huì)取出(索引、元素)對。使用者可視情況而用。
Perl
5新增了參考指標(biāo)的資料型態(tài),使Perl和C一樣可借由指標(biāo)建立一些復(fù)雜的資料結(jié)構(gòu)。普通程式是用不到指標(biāo)這玩意的,下面也只是簡單介紹一下,看不懂的人可不必深究。
⊙如何取得變數(shù)的位址?
Perl 也有和 C 一樣以 "\" 開頭的特殊字元: 另外需要說明的是 Perl 融合了 unix shell script
的使用慣例,以雙引號("")括起來的字串會(huì)先經(jīng)過展開,但反斜線(\)後面的字元?jiǎng)t不展開,當(dāng)作一般字元看待。而以單引號('')括起來的字串完全不會(huì)展開,以反單引號(``)括起來的字串會(huì)把它當(dāng)作命令列指令一樣執(zhí)行,等於system()一樣。初學(xué)者常常會(huì)搞混,但習(xí)慣之後就會(huì)覺得不這樣分清楚反而不行哩。舉個(gè)例吧:
Regular
Expression通常是用來尋找特定的字串樣式(pattern),也就是所謂格式辨認(rèn)(pattern-matching)的功能。它的運(yùn)算子是『=~』和『!~』,可以把它念做match和not
match。
Syntax: $string =~ /regular expression/expression modifier
例:$sentence =~ /Hello/
例:
例:# 井字號開頭的後面都是注解。
#
純量變數(shù)以$開頭。
# my 是一種宣告變數(shù)的方式,它可以使變數(shù)區(qū)域化。
# 宣告變數(shù)時(shí)若不加 my 或 local
則Perl會(huì)把它當(dāng)作全域變數(shù)使用。
# 習(xí)慣上,我們會(huì)將字串用雙引號括起來,而數(shù)值就不用加引號。
my $x="abc";
my
$x=123;
my $x=4.56;
那麼程式怎麼判斷這是數(shù)值還是字串呢?
其實(shí)不是程式判斷,而是你自己要判斷。Perl分別提供了一堆運(yùn)算子來處理數(shù)字和字串,你必須知道這個(gè)變數(shù)是數(shù)值或字串,才能使用個(gè)別的運(yùn)算子來對變數(shù)做運(yùn)算。我分別列出字串運(yùn)算子和數(shù)值運(yùn)算子,好讓大家能區(qū)分它們的不同。
String Operator
Purpose
x
Returns a string consisting of the string on the left of the operand,
repeated the number of times of the right operand.
.
Concatenates the two strings on both sides of the operator.
eq
Returns True if the two operands are equivalent, False otherwise.
ne
Returns True if the two operands are not equal, False otherwise.
le
Returns True if the operand on the left is stringwise less than the
operand on the right of the operator. Returns False otherwise.
lt
Returns True if the operand on the left is stringwise less than or
equal to the operand on the right of the operator. Returns False
otherwise.
ge
Returns True if the operand on the left is stringwise greater than or
equal to the operand on the right of the operator. Returns False
otherwise.
gt
Returns True if the operand on the left is stringwise greater than the
operand on the right of the operator. Returns False otherwise.
cmp
Returns -1, 0, or 1 if the left operand is stringwise less than, equal
to, or greater than the right operand.
,
Evaluates the left operand, the evaluates the right operand. It
returns the result of the right operand.
++
Increments the string by one alphabetic value.
Value Operator
Purpose
+
Computes the additive value of the two operands.
-
Computes the difference between the two operands.
*
Computes the multiplication of the two operands.
/
Computes the division between the two operands.
%
Computes the modulus(remainder) of the two operands.
= =
Returns Ture if the two operands are equivalent, False otherwise.
!=
Returns Ture if the two operands are not equal, False otherwise.
<=
Returns Ture if the operand on the left is numerically less than or
equal to the operand on the right of the operator. Returns False
otherwise.
=>
Returns Ture if the operand on the left is numerically greater than or
equal to the operand on the right of the operator. Returns False
otherwise.
<
Returns Ture if the operand on the left is numerically less than the
operand on the right of the operator. Returns False otherwise.
>
Returns Ture if the operand on the left is numerically greater than
the operand on the right of the operator. Returns False otherwise.
< = >
Returns -1 if the left operand is less than the right, +1 if is it
greater than, and 0(False) otherwise.
&&
Performs a logical AND operation. If the left operand is True m then
the right operator is not evaluated.
||
Performs a logical OR operation. If the left operand is True m then
the right operator is not evaluated.
&
Returns the valueof the two operators bitwise ANDed.
|
Returns the valueof the two operators bitwise ORed.
^
Returns the valueof the two operators bitwise XORed.
++
Increment operator. Increments the variable's value by 1.
--
Decrement operator. Decrements the variable's value by 1.
**
Computes the power of the left-hand value to the power of the
rihght-hand value.
+=
Adds the value of the right-hand operand to the value of the left-hand
operand.
-+
Subtracts the value of the right-hand operand to the value of the
left-hand operand.
*=
Mlutiplies the value of the left-hand operand to the value of the
right-hand operand.
>>
Shifts the left operand right by the number of bits that is specified
by the right operand.
<<
Shifts the left operand left by the number of bits that is specified
by the right operand.
~
Performs a 1s complement of the operator. This is a unary operator.
# 純量陣列以 @ 開頭。
my @array;
my @array=qw(a b c d);
# qw
函數(shù)會(huì)將其後的每個(gè)元素用逗點(diǎn)隔開,效果就像下面這行。
my @array=("a","b","c","d");
#
當(dāng)然你也可以一個(gè)個(gè)元素宣告,下面就是存取每一個(gè)元素的方法。
# 因?yàn)殛嚵兄械拿恳粋(gè)元素都是純量變數(shù),所以要以 $ 開頭,
#
剛開始容易搞混,請注意。
$array[0]="a"; $array[1]="b"; $array[2]="c";
$array[3]="d";
# 使用for loop印出陣列內(nèi)每個(gè)元素的值。
for($i=0; $i<=$#array;
$i++) {
print "$array[$i]\n";
}
看到$#array這個(gè)奇怪的東東沒?
這是Perl的一個(gè)特殊用法,代表這個(gè)陣列最後一個(gè)元素的注標(biāo)。由於Perl不必事先宣告變數(shù),也不必預(yù)先宣告陣列的大小,甚至可以隨時(shí)增加新元素,那我們怎麼知道這個(gè)陣列到底有多大呢?
透過這個(gè)特殊變數(shù)我們可以得知這個(gè)這個(gè)陣列最後一個(gè)元素的注標(biāo),自然而然也就知道這個(gè)陣列究竟有多大了。另外Perl只定義了一維陣列的語法,二維以上只能用指標(biāo)間接來達(dá)成。
# 相關(guān)陣列是以 % 符號開頭的。
my %hash;
#
=> 這個(gè)符號是Perl5新增的,是為了相關(guān)陣列量身定做的,
# 因?yàn)樗饕驮刂刀际羌兞,若使?=> 這個(gè)符號,
#
(索引=>元素值) 兩兩對應(yīng),就不容易發(fā)生失誤。
my
%hash=("i1"=>"aaa","i2"=>"bbb","i3"=>"ccc");
#
上面這行的效果和下面這行是一樣的。
my %hash=("i1","aaa","i2","bbb","i3","ccc");
#
下面是存取每個(gè)元素的方法,注意是用大括號把索引括起來哦。
# 習(xí)慣上索引值用單引號、元素值用雙引號括起來。
$hash{'i1'}="aaa";
$hash{'i2'}="bbb"; $hash{'i3'}="ccc";
# 下面是使用相關(guān)陣列的三個(gè)例子:
foreach $key
(keys %hash) {
print "$hash{$key}\n";
}
foreach $value (values
%hash)
while(($key,$value)=each %hash)
$scalarRef=\$scalarVar;
$arrayRef=\@arrayVar;
$hashRef=\%hashVar;
$funcRef=\&funcName;
print $$scalarRef;
print "@$arrayRef";
print
$hashRef->{$key};
&$funcRef;
$arrayRef=[[1,2,3,4],a,b,[x,y,z],c];
print
"$arrayRef->[0][0]\t$arrayRef->[2]\t$arrayRef->[3][2]\n";
$hashRef={a=>aa,b=>bb,c=>cc};
print
"$hashRef->{a}\t$hashRef->\t$hashRef->{c}\n";
(2) 控制敘述(Control Statements)
# Expression
就是條件敘述式,Perl和C一樣沒有定義布林資料型態(tài)(Boolean data type),
# 因此 0 是false、非0
是ture。另外要注意字串運(yùn)算子和數(shù)值運(yùn)算子要分清楚哦。
# Code Segment 就是用大括號括起來的一堆指令,也就是一個(gè)Block。
if
(Expression) {Code Segment}
if (Expression) {Code Segment} else {Code
Segment}
if (Expression) {Code Segment} elsif (Expression) {Code
Segment} else {Code Segment}
# elsif 就是 else if
#
如果指令(statement)只有一項(xiàng),我們可以使用倒裝句法,看起來比較簡潔。
statement if
(Expression);
# unless 就是if not
statement unless
(Expression);
例:
print "HELLO!\n" if ($name eq "friend");
$x-=10 if ($x
== 100);
看吧! C 語言有的Perl大部分都有,學(xué)過 C 的人可以毫不費(fèi)力的學(xué)會(huì)Perl。
# 注意:純量變數(shù)前面要加個(gè) $ 字號,這一點(diǎn)和C語言不一樣哦。
Perl還有提供label(標(biāo)記)的語法,也就是 goto
指令,不過有經(jīng)驗(yàn)的programer并不喜歡用它,我也不建議大家使用,所以就此按下不講。有興趣的人請自行查閱。還有一點(diǎn)值得注意的是Perl沒有提供像C語言一樣的
switch 敘述,不過Perl的pattern match的功能非常強(qiáng),所以我建議你直接用 if else 敘述來做就好了。
for($i=0;
$i<=10; $i++) {Code Segment}
# foreach 是承襲UNIX的shell script來的,
#
第一個(gè)引數(shù)是純量變數(shù),第二個(gè)引數(shù)要用括號括起來,里面是一個(gè)純量陣列,
# 顧名思義它就是把陣列中的每個(gè)元素依序傳給第一個(gè)引數(shù),直到全部傳完。
#
它和 for($i=0; $i<=$#array; $i++) 用法雖然不同,但目的都是要取出陣列的每個(gè)元素。
foreach $i
(@array) {Code Segment}
# 其實(shí)在Perl中,for和foreach是可以混著用的,就看個(gè)的人習(xí)慣了。
#
下面這行就等於上面第一個(gè)敘述,不過簡潔多了,大家可以試著用用看。
for $i (0..10) {Code Segment}
#
while控制回圈和後置回圈。
while($i<=10) {Code Segment}
do {Code Segment}
while(Expression);
# Perl也有和C語言的break和continue一樣的指令,Perl叫它做 last 和 next
(較口語化)。
#
last是跳出現(xiàn)在所在的回圈,next則是跳過下面的指令直接執(zhí)行下一次的回圈。
while(chomp($i=<STDIN>))
{
next if ($i == 5);
last unless ($i >
10);
}
(3)
副程式(Subroutines)
my ($a1,$a2,$a3,...) = @_;
來取出各個(gè)參數(shù),當(dāng)然 my @arg=@_;
或 my %arg=@_;
也是可以的。由於Perl的語法非;顫,使得程式在維護(hù)時(shí)特別棘手,因此寫注解成為一項(xiàng)很重要的工作。我建議你最好在每個(gè)副程式前面加上對這段副程式的描述,特別是需要傳遞的參數(shù)要注明清楚。
my
$x=3;
,若副程式所用的變數(shù)名不小心和主程相同,Perl會(huì)以目前正在執(zhí)行的副程式里的變數(shù)為優(yōu)先。
(4) I/O和檔案處理
close(FILEHANDLE);
Expression
Effect
open(FH, "<filename")
Opens filename for reading.
open(FH, "+<filename")
Opens filename for both reading and writing.
open(FH, ">filename")
Opens filename for writing.
open(FH, "+>filename")
Opens filename for both reading and writing.
open(FH, ">>filename")
Appends to filename.
open(FH, "command|")
Runs the command and pipes its output to the filehandle.
open(FH, "command|")
Pipes the output along the filehandle to the command.
open(FH, "-")
Opens STDIN.
open(FH, ">-")
Opens STDOUT.
open(FH, "<&=N")
Where N is a number, this performs the equivalent of C's fdopen for
reading.
open(FH, ">&=N")
Where N is a number, this performs the equivalent of C's fdopen for
writing. 例:
# 開啟$filename這個(gè)檔案,若開啟失敗則印出die後面的訊息,并結(jié)束程式。
open(FILE,
$filename) || die "Can't open file $filename : $!\n";
# 下面是一個(gè)十分精簡的寫法,和
while($_=<FILE>){print "$_";} 是等效的。
print while(<FILE>);
#
檔案開啟後要記得隨手關(guān)閉,這才是寫程式的好習(xí)慣。
close(FILE);
#
$!和$_都是Perl的特殊變數(shù),下面會(huì)介紹的。
#
Perl不會(huì)自動(dòng)去掉結(jié)尾的CR/LF,跟C語言不同,所以要用chomp函數(shù)幫你去掉它。
#
大家常常會(huì)忘記這個(gè)動(dòng)作,導(dǎo)致結(jié)果跟你想的不一樣,要特別注意一下。
$input=<STDIN>; chomp $input;
#
下面是較簡潔的寫法。
chomp($input=<STDIN>);
# 不用再指定變數(shù)的data
type,這樣不是比printf()方便多了嗎?
print "Scalar value is $x\n";
# .
是字串加法的運(yùn)算子,上下這兩行是等效的。
print "Scalar value is " . $x . "\n";
#
輸出到檔案的方法。
print FILE "print $x to a file.";
# 下面是print的特殊用法,學(xué)自shell
script的用法:
print<<XXX;這招叫做 here document,XXX可以是你取的任何識別字,
在識別字之間的字都會(huì)按照你所寫的樣子輸出,就像<pre>標(biāo)簽一樣。
而當(dāng)一行的開頭是XXX你取的這個(gè)識別字時(shí),才會(huì)停止輸出。
XXX \t tab
\n newline
\r return
\f form feed
\b backspace
\a alarm(bell)
\e escape
\033 octalchar
\x1b hex char
\c[ control char
\l lowercase next char
\u uppercase next char
\L lowercase till \E
\U uppercase till \E
\E end case modification
\Q quoteregexp metacharacters till \E
$x="ls -l";
print "$x"; # Output ls -l
print "\$x"; # Output $x
print '$x'; # Output $x
print `$x`; # Output files in this directory
(5) Regular
Expressions
g
Match globally, i.e. find all occurrences.
i
Makes the search case-insensitive.
m
If the string has new-line characters embedded within it, the
metacharacters ^ and $ will not work correctly. This modifier tells Perl
to treat this line as a multiple line.
o
Only compile pattern once.
s
The character . matches any character except a new line. This modifier
treats this line as a single line, which allows . to match a new-line
character.
x
Allows white space in the expression.
\
Tells Perl to accept the following characters as a regular character;
this removes special meanings from any metacharacter.
^
Matches the beginning of the string, unless /m is used.
.
Matches any character except a new line character, unless /s is used.
$
Matches the end of the string, unless /m is used.
|
Expresses alternation. This means the expressions will search for
multiple patterns in the same string.
( )
Groups expressions to assist in alternation and back referencing.
[ ]
Looks for a set of characters.
*
Matchs 0 or more times.
+
Matchs 1 or more times.
?
Matchs 0 or 1 times.
{n}
Matches exactly n times.
{n,}
Matches at least n times.
{n,m}
Matches at least n times but no more than m times.
\r
Carriage return(CR), ASCII 13(十進(jìn)位)
\n
New line, UNIX中代表ASCII 10(十進(jìn)位), DOS(Windows)系統(tǒng)中則是ASCII 13 + ASCII
10(十進(jìn)位).
\t
Tab, ASCII 9(十進(jìn)位)
\w
Matches an alphanumeric character. Alphanumeric
also includes _. 即 [A-Za-z0-9_].
\W
Matches a nonalphanumeric character. 即 [^A-Za-z0-9_].
\s
Matches a white space character. This includes space,
tab, FormFeed and CR/LF. 即 [\ \t\f\r\n].
\S
Matches a non-whote space character. 即 [^\ \t\f\r\n].
\d
Matches a digit. 即 [0-9].
\D
Matches a nondigit character. 即 [^0-9].
\b
Matches a word boundary.
\B
Matches a nonword boundary.
\033
octal char
\x1B
hex char
/abc/
/^abc/
/abc$/
/a|b/
/ab{2,4}c/
/ab*c/
/ab+c/
/a.c/
/[abc]/
/\d/
/\w/
/\s/
/[^abc]/
/\*/
/abc/i
/(\d+)\.(\d+)\.(\d+)\.(\d+)/
if ($x =~ /(\d+\.\d+)\.\d+\.\d+/) {
print
"海洋大學(xué)" if ($1 eq "140.121");
}m//gimosx
$url="my.machine.tw:8080/cgi-bin/test.pl";
這個(gè)Regular
Expression相當(dāng)復(fù)雜,主要目的是分析指定的URL,然後取得host名稱、port號碼及對應(yīng)的檔案。我一項(xiàng)項(xiàng)慢慢解釋:
($host, $port,
$file)=($url=~m|http://([^/:]+):{0,1}(\d*)(\S*)$|);
$url=~m||
m後面跟著的就是分隔符號,|
|里面的就是pattern。
([^/:]+)
match一個(gè)字串,里面沒有/和:字元。找到的字串存在$1中。
:{0,1}(\d*)
match
0或1個(gè):,後面跟著一串?dāng)?shù)字或nothing。找到的字串存在$2中,若找不到,$2就是空的。
(\S*)$
match一串非空白字元,并以找到的字串為結(jié)尾。找到的字串存在$3中。
()=()
($host, $port,
$file)=($1, $2,
$3)
即$host="my.machine.tw"
$port=8080
$file="/cgi-bin/test.pl"
s/PATTERN/REPLACEMENT/egimox
e
Evaluate the right side as an expression.
g
Replace globally, i.e. all occurrences.
i
Do case-insensitive pattern matching.
m
Treat string as multiple lines.
o
Only compile pattern once.
s
Treat string as single line.
x
Use extended regular expressions. $x =~
s/\s+//g
把所有的white space全部去除掉
$x =~ s/([^ ]*):*([^
]*)/$2:$1/
把用":"分開的兩個(gè)欄位互相對調(diào)
$path =~
s|/usr/bin|/usr/local/bin|
它也可以讓你自訂分隔符號哦
tr/SEARCHLIST/REPLACEMENTLIST/cds
c
Complement the SEARCHLIST.
d
Delete found but unreplaced characters.
s
Squash duplicate replaced characters. $x =~
tr/this/that/
把"this"替換成"that"
$x =~
tr/a-z/A-Z/
把小寫字母全部替換成大寫字母
$count = $x =~
tr/*/*/
計(jì)算$x中有幾個(gè)"*"