Perl的基本语法及常见变量
2009-12-01 13:54:07 阿炯

这篇文章是花了我很多时间、费了我很多心血才完成的,虽然连我自己都觉得无法达到尽善尽美的境界,但希望能帮助大家入门,稍微了解到Perl到底是个什么样的东西,Perl到底有那些强大的功能,那么这篇文章的目的就达到了。我分做数据型态、控制叙述、子程序、I/O和档案处理、正则表达式、特殊变量、帮助这几部分来讲解,但只是叙述了一些Perl的基本语法而已,Perl活泼的特性和程序的技巧就无法一一详述了,甚为缺憾。

前言:

说起编程语言,简单的来说无非就是这样几个必不可少的基本元素:变量、数据、表达式、流程控制语句(包括条件、分支、循环)、函数、对象。具体到语言上,大部分的内容只是表达的形式不同而已。而PerlC又有什么区别呢?

首先要知道,Perl是一种脚本语言。所谓的脚本,就是没有主函数,从最开始一行一行的按照顺序解释执行。因此,尽管把你的思路转化为流程用Perl表达出来吧。

其次,Perl的设计中参考了很多语言的长处,并避免了设计上的缺陷。因此Perl的很多语法你可能都会觉得似曾相识。我把Perl的语法总结了一下,和C语言做了一个简单的对比表格。表格左右两边的语句是CPerl对应表达同一个功能各自的不同方式。如果读者有C语言的经验,相信看到这个对比可以很快的上手吧?

语法元素

C

Perl

Perl语法说明

注释

/* … */

# …

只支持单行注释

变量

int a, b, c;

char c=’A’;

int x[10];

my ($a, $b, $c);

my $c='A';

my @x;

my %h;

声明使用my标示

表示值的变量以$开头,表示数组的变量以@开头,表示哈希表的变量以%开头。

声明可以省略(不建议)

字符串

char* h1=”hello\n”;

char* h2=”hello\\n”;

$h1=”hello\n”;

$h2=’hello\n’;

双引号解释内部的\n,而单引号则不解释

一维数组

int arr[10];

arr[0]=0;

for(i=0;i<10;i++)

arr[i]=i;

my @arr;

$arr[0]=0;

@arr[3..5]=(3..5);

数组声明以@标示

动态数组,不需要指定大小

数组下标从0开始

访问数组元素值的时候,要以$开头表示访问的是数值

[3..5]表示数组中下标为35之间的元素组成的数组,数组之间可以直接赋值

多维数组

int arr[10][10];

arr[0][1]=9;

my @arr;

$arr[0][1]=9;

Perl并不直接支持多维数组,而是以数组引用的方式间接支持。例如arr[0]的内容就是一个数组的引用地址。

指针

char c;

int* x=&c;

c='a';

printf(*x);

my $c;

my $x=\$c;

$c='a';

print $x;

\C中的&类似,意思是取引用

函数

void hello() {

printf(“Hello\n”);

}

void (*hi)()=hello;

(*p)();

sub hello{

print "Hello\n";

}

my $hi = *hello;

&$hi;

&表示调用函数

*取函数的代码地址

不必用括号把参数括起来

调用时的括号也是可选的

条件语句

if (x>0) x=0;

x>0 ? x=0 : ;

if ($x>0) { $x=0; }

$x=0 if $x>0;

$x=0 unless $x<=0;

$x>0 ? $x=0 : ;

if 结构可以反转,意义不变,注意前句没有分号。

顾名思义, unless是“除非”的意思。这里的四个表达方式是等价的。注意第一种方式中,条件部分的圆括号和语句部分的花括号是不可省略的。

循环语句

foreach (@arry)

foreach my $key(@ary)

foreach $count (1..10)

for/while的语法都和C类似。

foreach关键字也可以用for,意义不变。

函数

int max(int x, int y){

return x>y?x:y;

}

int n=max(1,2);

sub max{

my ($x, $y)=@_;

return $x>$y?$x:$y;

}

my $n=max(1,2)

注意下划线”_”也是一个合法的变量名。而@_Perl内置的一个数组,内容为函数的参数。

my ($x, $y) 表示声明了一个有两个元素的数组,并将两个元素映射到$x$y上。

($x,$y)=@_;则表示两个数组之间的复制,@_中对应的元素的值就赋值给了$x$y.这是一个简便的写法,也可以这样写

my $x=$_[0]; my $y=$_[1];

return是可选的,默认返回最后一个表达式的值

语法约束

1. 编译时打开编译器所有的警告选项

2. 使用lint工具

3. perl –w myprogram.pl 打开运行警告开关,如果运行时Perl检查到了可能的错误,会显示警告信息,否则它默认是什么也不提示继续执行。

4. #!/usr/bin/perl –w 在代码文件第一行中加入-w选项开关

5. use strict; 使用严格语法约束

运行

编译后直接执行

1. perl myprogram.pl 手工执行

2. #!/usr/bin/perl

Unix下在代码第一行加入,然后给文件加上可执行的属性 chmod +x myprogram.pl,之后就可以用./myprogram.pl命令来运行。

3. Windows下,安装ActivePerl的时候,已经将.pl后缀的文件和perl的解释程序关联起来了,因此直接双击文件图标就可以运行。

需要说明的是,在Perl的世界中有一句名言“条条大路通罗马”,这句话的意思是说同样一件事情Perl允许你用很多种不同的方式去做。因此上表的例子风格是按照C的习惯来写的,并且为了简化起见,只是挑选了与C相似的内容。事实上,Perl包含了很多C没有的东西,例如内置的Hash表、队列、正则表达式、格式定义等等。

(1)、数据型态(Data type)

Perl的数据型态大致分为四种:ScalarScalar ArrayHash ArrayReferences,看起来虽少但用起来却绰绰有余。尤其在写Perl程序时可以不必事先宣告变量,这一点对刚学程序语言的人甚为方便,不过为了以后程序除错和维护方便,我建议你还是养成事先宣告变量的习惯比较好。

(a) Scalar

纯量变量是Perl里最基本的一种数据型态,它可以代表一个字符、字符串、整数、甚至浮点数,而Perl把它们都看成是一样的东东! 你甚至可以混着用,不可思议吧。例如:

# 井字号开头的后面都是批注。

# 纯量变数以$开头。

# my 是一种宣告变量的方式,它可以使变量区域化。

# 宣告变量时若不加 my local Perl会把它当作全域变量使用。

# 习惯上,我们会将字符串用双引号括起来,而数值就不用加引号。

my $x="abc";

my $x=123;

my $x=4.56;

那么程序怎么判断这是数值还是字符串呢? 其实不是程序判断,而是你自己要判断。Perl分别提供了一堆运算子来处理数字和字符串,你必须知道这个变量是数值或字符串,才能使用个别的运算子来对变量做运算。我分别列出字符串运算子和数值运算子,好让大家能区分它们的不同。

◎字符串运算子

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.

(b) Scalar Array

纯量数组,数组内的每一个元素都是Scalar variable。宣告及使用方式如下:

# 纯量数组以 @ 开头。

my @array;

my @array=qw(a b c d);

# qw 函数会将其后的每个元素用逗点隔开,效果就像下面这行。

my @array=("a","b","c","d");

# 当然你也可以一个个元素宣告,下面就是存取每一个元素的方法。

# 因为数组中的每一个元素都是纯量变量,所以要以 $ 开头,

# 刚开始容易搞混,请注意。

$array[0]="a"; $array[1]="b"; $array[2]="c"; $array[3]="d";

# 使用for loop印出数组内每个元素的值。

for($i=0; $i<=$#array; $i++) {

print "$array[$i]\n";

}

看到$#array这个奇怪的东东没? 这是Perl的一个特殊用法,代表这个数组最后一个元素的注标。由于Perl不必事先宣告变量,也不必预先宣告数组的大小,甚至可以随时增加新元素,那我们怎么知道这个数组到底有多大呢? 透过这个特殊变量我们可以得知这个数组最后一个元素的注标,自然而然也就知道这个数组究竟有多大了。另外Perl只定义了一维数组的语法,二维以上只能用指标间接来达成。

(c) Hash Array(Associative Array)

杂凑数组也叫做相关数组,它和一般数组没什么不同,差别只是在它的索引值用的是字符串,而非一般数组所用的整数值,因此相关数组不像一般数组一样有次序的概念,它没有所谓的第一项数据这种说法。它就相当于把一堆变量组合成一个group,然后我们可以透过索引字符串存取这个group每一个元素的值。相关数组的宣告及使用方式如下:

# 相关数组是以 % 符号开头的。

my %hash;

# => 这个符号是Perl5新增的,是为了相关数组量身定做的,

# 因为索引和元素值都是纯量,若使用 => 这个符号,

# (索引=>元素值) 两两对应,就不容易发生失误。

my %hash=("i1"=>"aaa","i2"=>"bbb","i3"=>"ccc");

# 上面这行的效果和下面这行是一样的。

my %hash=("i1","aaa","i2","bbb","i3","ccc");

# 下面是存取每个元素的方法,注意是用大括号把索引括起来哦。

# 习惯上索引值用单引号、元素值用双引号括起来。

$hash{'i1'}="aaa"; $hash{'i2'}="bbb"; $hash{'i3'}="ccc";

# 下面是使用相关数组的三个例子:

foreach $key (keys %hash) {

print "$hash{$key}\n";

}

foreach $value (values %hash)

while(($key,$value)=each %hash)

Perl有上述三个函数可对相关数组做运算:keys函数可取出相关变量的索引值,组成一纯量数组,注意这些由keys函数取出的索引值没有次序性;values函数可取出相关变量的元素值;each函数则会取出(索引、元素)对。使用者可视情况而用。

(d) References(Pointer)

Perl 5新增了参考指针的数据型态,使PerlC一样可借由指针建立一些复杂的数据结构。普通程序是用不到指针这玩意的,下面也只是简单介绍一下,看不懂的人可不必深究。

⊙如何取得变量的地址?

$scalarRef=\$scalarVar;

$arrayRef=\@arrayVar;

$hashRef=\%hashVar;

$funcRef=\&funcName;

⊙如何使用指标?

print $$scalarRef;

print "@$arrayRef";

print $hashRef->{$key};

&$funcRef;

Anonymous Array References(二维数组)

$arrayRef=[[1,2,3,4],a,b,[x,y,z],c];

print "$arrayRef->[0][0]\t$arrayRef->[2]\t$arrayRef->[3][2]\n";

Anonymous Hash References

$hashRef={a=>aa,b=>bb,c=>cc};

print "$hashRef->{a}\t$hashRef->{b}\t$hashRef->{c}\n";

(2)、控制叙述(Control Statements)

(a) 条件控制语句(Conditional Control Statements)

Perl的条件控制叙述和C语言很像,让使用者很快就能掌握它。不过PerlC语言又另外多了些实用的语法,我用底线标出来,大家一看便知:

# Expression 就是条件叙述式,PerlC一样没有定义布尔数据型态(Boolean data type)

# 因此 0 false、非0 ture。另外要注意字符串运算子和数值运算子要分清楚哦。

# Code Segment 就是用大括号括起来的一堆指令,也就是一个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)只有一项,我们可以使用倒装句法,看起来比较简洁。

statement if (Expression);

# unless 就是if not

statement unless (Expression);

例:

print "HELLO!\n" if ($name eq "friend");

$x-=10 if ($x == 100);

看吧! C 语言有的Perl大部分都有,学过 C 的人可以毫不费力的学会Perl

(b) Loop Control Statements

Perl的循环控制叙述也和C语言很像,当然,照例Perl也另外多了些实用的语法:

# 注意:纯量变数前面要加个$字号,这一点和C语言不一样哦。

for($i=0; $i<=10; $i++) {Code Segment}

for结构

for结构是各种语言中都有的。perl中的for结构和c语言中的非常相近。下面是一个例子。

#!/user/bin/perl -w

use strict;

{

my $a;

for($a=0;$a<10;$a++){

print "$a ";

}

}

对于数组我们可以这样访问。

#!/user/bin/perl -w

use strict;

{

my @a=(1..10);

my $counter;

for($counter=0;$counter<@a;$counter++){

print "$a[$counter] ";

}

}

这里面出现了一句$counter<@a,记住,数组在标量情况下即@a返回的是数组的长度,这样就好懂了,是不是?

# foreach 是承袭UNIXshell script来的,

# 第一个自变量是纯量变数,第二个自变量要用括号括起来,里面是一个纯量数组,

# 顾名思义它就是把数组中的每个元素依序传给第一个自变量,直到全部传完。

# 它和 for($i=0; $i<=$#array; $i++) 用法虽然不同,但目的都是要取出数组的每个元素。foreach $i (@array) {Code Segment}

foreach控制结构

foreach控制结构很好的,在bshjavascript中有一种for(in)循环和foreach很相象。foreach的用法可以从下面的例子得知:

#!/user/bin/perl -w

use strict;

my @a=(1..10);

my $counter;

foreach $counter (@a){

print "$counter ";

}

这个程序将会把@a数组中所有的元素先逐个引用给$counter,然后把$counter地值打印出来。注意,我这里说得是引用,不是赋值,perl里面的“=”实际上是在进行引用,而不是赋值,这是需要同c严格区分的。下面的例子更加好玩一点,看一看:

#!/user/bin/perl -w

use strict;

my @a=(1..10);

my $counter;

foreach $counter (@a){

$counter++;

}

print "@a ";

猜一猜将会打印出什么?呵呵,是234567891011。因为,$counter@a中每个元素的引用,所以$counter++就对@a中每个元素进行了++操作。foreach用在hash中是非常爽的。

#!/user/bin/perl -w

use strict;

my %a=(hello,"你好",great,"太棒了");

my $thiskey;

foreach $thiskey (keys %a){

print "$thiskey=>$a($thiskey) ";

}

将可以把hash中所有的keyvalue打印出来。

# 其实在Perl中,forforeach是可以混着用的,就看个的人习惯了。

# 下面这行就等于上面第一个叙述,不过简洁多了,大家可以试着用用看。

for $i (0..10) {Code Segment}

# while控制循环和后置循环。

while($i<=10) {Code Segment}

do {Code Segment} while(Expression);

while结构

while结构在perl中有三种形式。 第一种形式是这样的:

#!/user/bin/perl -w

use strict;

{

my $a=0;

while(3>$a){

print $a++;

print " ";

}

}

第二种是定语后置式。呵呵,英文好的觉得很正常了。

use strict;

{

my $a=0;

print $a++." " while(3>$a);

}

第三种是这个样子的,很古怪,真的很古怪。这种用法就是加上一个continue

#!/user/bin/perl -w

use strict;

my $a=0;

while(3>$a){

print "$a ";

}

continue{

if($a++>1) print "hello ";

}

这种结构会在每个while运行了一圈之后运行一遍continue的部分,然后继续进行while循环。UntilWhile的反义词,就是说不执行后面的语句一直到满足条件为止。如下面的例子

#!/usr/bin/perl -w

use strict;

my $a;

for($a=0;$a<0;$a++){

until($a==3)

{ print "$a " unless($a>5);

$a++;

}

}

这一段程序打印出3,好像很无聊是吧?但是有时候会有用的。这里有一个需要注意的是在until 里面有一个$a++。没有这个就会……555,死循环了。

# Perl也有和C语言的breakcontinue一样的指令,Perl叫它做 last next (较口语化)redo语法。

# last是跳出现在所在的循环,next则是跳过下面的指令直接执行下一次的循环。

while(chomp($i=)){

next if ($i == 5);

last unless ($i > 10);

}

Perl还有提供label(标记)的语法,也就是 goto 指令,不过有经验的programer并不喜欢用它,我也不建议大家使用,所以就此按下不讲。有兴趣的人请自行查阅。还有一点值得注意的是Perl没有提供像C语言一样的 switch 叙述,不过Perlpattern match的功能非常强,所以我建议你直接用 if else 叙述来做就好了。redo是一个很好玩的东西,这个家伙居然会让当前的一圈循环重新进行一次。但是我到现在都没有发现这个东西有什么用。下面的例子说明了redo的用法。

#!/usr/bin/perl -w

use strict;

my $x;

for($x=0;$x<5;){

$x++;

redo if($x==4);

print "$x ";

}

会打印1 2 3 5,呵呵,这个结果是很有趣的啊。当$x==3的时候,$x++结果是4,然后发生了redo,结果4就没打印出来。然后下一次循环开始了。这个时候又发生了一次$x++; 结果$x变成5了,然后打印出来。然后条件检测不通过,退出循环。

如果把上面的循环改成

for($x=0;$x<5;$x++){

redo if($x==4);

print "$x ";

}

则在我的机器上面发生了死循环。

(3)、子程序(Subroutines)

(a) Syntax: sub NAME {Code}

(b) 呼叫子程序: &NAME(para1, para2,...)

(c) 参数传递: @_

PerlC一样是采用Call by value的方式,不过因为Perl不用事先宣告变量,所以建立子程序的时候也不用宣告要传递什么参数。当主程序在传递参数给子程序时,Perl会把括号括起来的参数按顺序放在一个特殊的全域变量 @_ 数组中,然后子程序就可以随意使用数组 @_ 里的参数,例如 $_[0] 是第一个参数, $_[1] 是第二个,或是用 my ($a1,$a2,$a3,...) = @_;来取出各个参数,当然 my @arg=@_; my %arg=@_; 也是可以的。由于Perl的语法非常活泼,使得程序在维护时特别棘手,因此写批注成为一项很重要的工作。我建议你最好在每个子程序前面加上对这段子程序的描述,特别是需要传递的参数要注明清楚。

(d) Variable Localizationmy or local

通常我们在程序中定义的变量都是全域变量,所以在子程序中若要把变量区域化则要加上 my local 关键词,例如: my $x=3;,若子程序所用的变量名不小心和主程相同,Perl会以目前正在执行的子程序里的变量为优先。

(4)、I/O和档案处理

(a) Syntax:

open(FILEHANDLE,"Expression");

close(FILEHANDLE);

这里的Expression是一个叙述加上文件名称,若Expression只有文件名称没有加上叙述,则预设是只读。Expressions叙述如下:

Expression Effect

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这个档案,若开启失败则印出die后面的讯息,并结束程序。

open(FILE, $filename) || die "Can't open file $filename : $!\n";

# 下面是一个十分精简的写法,和 while($_=){print "$_";} 是等效的。

print while();

# 档案开启后要记得随手关闭,这才是写程序的好习惯。

close(FILE);

# $!$_都是Perl的特殊变数,下面会介绍的。

(b) Input

Perl没有特别用来输入的函数,因为Perl在执行程序时,会自动开启标准输入装置,其filehandle定为STDIN,所以在Perl中要输入数据的方法就是使用:

# Perl不会自动去掉结尾的CR/LF,跟C语言不同,所以要用chomp函数帮你去掉它。

# 大家常常会忘记这个动作,导致结果跟你想的不一样,要特别注意一下。

$input=<STDIN>; chomp $input;

# 下面是较简洁的写法。

chomp($input=<STDIN>);

(c) Outputprint "variables or 字符串";

Perl也有printf()函数,语法和C语言一模一样,我就不多做介绍了。Perl另外有个print函数,比printf()更方便、更好用,包你爱不释手。Output不外乎是输出到屏幕或档案,用例子来说明比较容易了解。

# 不用再指定变量的data type,这样不是比printf()方便多了吗?

print "Scalar value is $x\n";

# . 是字符串加法的运算子,上下这两行是等效的。

print "Scalar value is " . $x . "\n";

# 输出到档案的方法。

print FILE "print $x to a file.";

# 下面是print的特殊用法,学自shell script的用法:

print<

这招叫做 here documentXXX可以是你取的任何标识符,在标识符之间的字都会按照你所写的样子输出,就像\标签一样。而当一行的开头是XXX你取的这个标识符时,才会停止输出。

XXX

Perl 也有和 C 一样以 "\" 开头的特殊字符:

\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

另外需要说明的是 Perl 融合了 unix shell script 的使用惯例,以双引号("")括起来的字符串会先经过展开,但反斜线(\)后面的字符则不展开,当作一般字符看待。而以单引号('')括起来的字符串完全不会展开,以反单引号(``)括起来的字符串会把它当作命令列指令一样执行,等于system()一样。初学者常常会搞混,但习惯之后就会觉得不这样分清楚反而不行哩。举个例吧:

$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)

Regular Expression通常是用来寻找特定的字符串样式(pattern),也就是所谓格式辨认(pattern-matching)的功能。它的运算子是『=~』和『!~』,可以把它念做matchnot match

Syntax: $string =~ /regular expression/expression modifier

例:$sentence =~ /Hello/

(a) Modifiers:修饰选项可有可无,它是用来对整个叙述作修正的。

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.

(b) Metacharacter:下面这些字符都具有特殊意义,可以让你建立更复杂的搜寻样式(searching pattern)

\ 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.

(c) Pattern Quantifier:用来表示字符的数量关系。

* 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.

(d) Character Patterns:下列的sequence用来match一些特定格式的字符:

\r Carriage return(CR), ASCII 13(十进制)

\n New line, UNIX中代表ASCII 10(十进制), DOS(Windows)系统中则是ASCII 13 + ASCII 10(十进制).

\t Tab, ASCII 9(十进制)

\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

(e) 示例:

Regular Expression这 个东东非常强大、非常重要,但是对初学者来说简直是个恶梦,记得我当初刚接触时也是雾煞煞的,就算现在的我也不敢说全懂了。但你若了解了它的基本技巧后, 包你爱不释手,每每为它强大的功能赞叹。上面那些表格相信你也是有看没有懂,这种东西要借由范例入门比较快,下面我列出一些基本范例,希望能帮助你了解它 的基本技巧。

/abc/

找到含有abc的字符串

/^abc/

找到开头是abc的字符串

/abc$/

找到结尾是abc的字符串

/a|b/

找到有ab的字符串,也可以用来找整个字(word)

/ab{2,4}c/

找到a后面跟着2-4b,再跟着c的字符串,若只有/ab{2,}c/则会找二个以上的b

/ab*c/

找到a后面跟着0个或多个b,再跟着c的字符串,如同/ab{0,}c/

/ab+c/

找到a后面跟着一个以上的b,再跟着c的字符串,如同/ab{1,}c/

/a.c/

.可以代表任何字符,除了new line字符(\n)外。

/[abc]/

找到含有这三个字符中任何一个的字符串

/\d/

找到含有数字的字符串,如同/[0-9]/

/\w/

找到含有字母的字符串,如同/[a-zA-Z0-9_]/

/\s/

找到含有white space的字符串,如同/[ \t\r\n\f]/

/[^abc]/

找到没有abc任一字符的字符串

/\*/

找到含有字符*的字符串,在反斜线"\"后面的字符Perl会把它当作普通字符看待。若你不确定这个符号是否为特殊字符,干脆全加上\以策安全。

/abc/i

忽略abc的大小写

/(\d+)\.(\d+)\.(\d+)\.(\d+)/

找到类似IP的字符串,并将IP的四个数字分别存在$1,$2,$3,$4四个特殊变数中,以便在其后加以利用。例:

if ($x =~ /(\d+\.\d+)\.\d+\.\d+/) {

print "海洋大学" if ($1 eq "140.121");

}

m//gimosx

m命令可以让你自订pattern的分隔符,而gimosx则是它的修饰选项,请参看(a)Modifiers。例如:

$url="my.machine.tw:8080/cgi-bin/test.pl";

($host, $port, $file)=($url=~m|http://([^/:]+):{0,1}(\d*)(\S*)$|);

这个Regular Expression相当复杂,主要目的是分析指定的URL,然后取得host名称、port号码及对应的档案。我一项项慢慢解释:

$url=~m||

m后面跟着的就是分隔符,| |里面的就是pattern

([^/:]+)

match一个字符串,里面没有/:字符。找到的字符串存在$1中。

:{0,1}(\d*)

match 01:,后面跟着一串数字或nothing。找到的字符串存在$2中,若找不到,$2就是空的。

(\S*)$

match一串非空格符,并以找到的字符串为结尾。找到的字符串存在$3中。

()=()

($host, $port, $file)=($1, $2, $3)

$host="my.machine.tw"

$port=8080

$file="/cgi-bin/test.pl"

s/PATTERN/REPLACEMENT/egimox

没错,这就是取代的命令。它会寻找符合PATTERN的字符串,并取代成REPLACEMENT字符串。它的修饰选项多了e选项,其它的和上面都一样,我将它列表如下:

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/

把用":"分开的两个字段互相对调

$path =~ s|/usr/bin|/usr/local/bin|

它也可以让你自订分隔符哦

tr/SEARCHLIST/REPLACEMENTLIST/cds

这是也是取代的命令,和上一个不同的是SEARCHLISTREPLACEMENTLIST只能是普通字符串,而不是Regular Expression,所以速度比较快。它的修饰选项也比较少:

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/*/*/

计算$x中有几个"*"

(6)、Spectial Variables(常见特殊变量)

Perl的特色之一就是有超过50个以上的特殊变量,这些变量都是全域变量,用来设定程序的执行环境和其它细节。若你想深入了解Perl程序设计,那么这些东西是不可或缺的。在这里我只列几个常用的特殊变量以供参考,有兴趣的人请自行查阅。

$_ The default input and pattern-searching space.

$digit Contains the subpattern from a successful parentheses pattern match.

$. The current input line number of last filehandle read.

$! Contains the current value of errno.

$0 The name of the file of the Perl script.

@ARGV The command line arguments issued when the script was started.

@_ The parameter array for subroutines.

%ENV This associative array contains your current environment.

1. $_

$ARG,常常是一个默认变量

2. @_

@ARG,子例程参数表

3. {row.content}

$PROGRAM_NAME,本程序的名字

4. @ARGV

本程序的命令行参数表

5. $"

$LIST_SEPARATOR,数组内插到双引号字符串中时所用的分隔符,

默认为空格

6. $,

$OFS,或$OUTPUT_FIELD_SEPARATOR,用于print的输出字段分隔符,

即一个print语句中用逗号分隔的部分之间用什么分隔,默认为无

7. $

$ORS,或$OUTPUT_RECORD_SEPARATOR,用于print的输出记录分隔符,

即一个print语句结束时末尾添加什么,默认为无

8. $/

$RS,或$INPUT_RECORD_SEPARATOR,输入记录分隔符,改变了readline

chomp对于“行”的看法,默认为换行符

9. $.

$NR,或$INPUT_LINE_NUMBER,最后读取的“行”号(注意行的概念可能

8所改变)

10. $|

$AUTOFLUSH,或$OUTPUT_AUTOFLUSH,输出缓冲区开关,默认为0,即关

11. $$

$PID,或$PROCESS_ID,本脚本的进程号(PID)

12. $!

$ERRNO,或$OS_ERROR,上一次系统调用错误值

13. $@

$EVAL_ERROR,上一次eval操作错误值

14. $^I

$INPLACE_EDIT,现场编辑的备份文件扩展名

15. %ENV

当前环境变量

16. 与正则表达式相关的几个量

||||

/ ------- mmmmmmmm ++++++++/ => 正则表达式(注意:空格不代表实际空格)

| |匹配部分|

0 ($-[0]) ($+[0])

17. $^O

操作系统名称。

或者

use English;

print $OSNAME;

或者

use Config;

print $Config{"osname"};


Perl内置变量表小结

PERl相对来说受关注的程度要低些,这里总结整理了PERL的部分内置变量,可以在程序中直接引用,希望对大家有所帮助。

$- 当前页可打印的行数,属于Perl格式系统的一部分

$! 根据上下文内容返回错误号或者错误串

$" 列表分隔符

$# 打印数字时默认的数字输出格式

$ Perl解释器的进程ID

$% 当前输出通道的当前页号

$Content$amp; 与上个格式匹配的字符串

$( 当前进程的组ID

$) 当前进程的有效组ID

$* 设置1表示处理多行格式.现在多以/s/m修饰符取代之.

$, 当前输出字段分隔符

$. 上次阅读的文件的当前输入行号

$/ 当前输入记录分隔符,默认情况是新行

$: 字符设置,此后的字符串将被分开,以填充连续的字段.

$; 在仿真多维数组时使用的分隔符.

$? 返回上一个外部命令的状态

$@ Perl解释器从eval语句返回的错误消息

$[ 数组中第一个元素的索引号

$\ 当前输出记录的分隔符

$] Perl解释器的子版本号

$^ 当前通道最上面的页面输出格式名字

$^A 打印前用于保存格式化数据的变量

$^D调试标志的值

$^E在非UNIX环境中的操作系统扩展错误信息

$^F最大的文件捆述符数值

$^H由编译器激活的语法检查状态

$^I内置控制编辑器的值

$^L发送到输出通道的走纸换页符

$^M备用内存池的大小

$^O操作系统名

$^P指定当前调试值的内部变量

$^R正则表达式块的上次求值结果

$^S当前解释器状态

$^T从新世纪开始算起,脚步本以秒计算的开始运行的时间

$^W警告开关的当前值

$^X Perl二进制可执行代码的名字

$_ 默认的输入/输出和格式匹配空间

$ 控制对当前选择的输出文件句柄的缓冲

$~ 当前报告格式的名字

(7)、帮助

目前市面上有关Perl语言的书并不多,就算是原文书也只有那几本圣经本。不过只要是有关CGI的书,其内容大都会提到Perl,但却很少教到基本语法,常常使人一头雾水。所以建议:如果真的想学好Perl语言,真得想拿Perl来写程序,那建议最好去买一本书来看,在观念上会比较清楚,在实际应用上也会比较有帮助;如果只是想写一些简单的CGI程序,或只想看得懂别人所写的CGI程序,那在网络上的资源就绰绰有余了。

首先你可以到各大BBS站的WWW板或Program板的精华区找找,不过数据不会很多,而且有点杂乱。再不然你可以到蕃薯藤输入perlcgi关键词找找,有不少人的主页上有教人如何用PerlCGI程序,还有一堆别人已经写好的CGI程序可以抓来用用。

第三种资源就是Perl本身的man pages,这些文件做得不错,还根据Perl的各个部分写了man pages,如Perl syntax, builtin function, regular expression, data structure等,大家可以用man指令一一查询,有时候在写程序时一时忘了某个函数怎么用,这倒是个方便又快速的查询方法。我会把这些man pages转成html格式,放在Web站点上让大家参考。

该文章最后由 Administrator 于 2021-08-17 16:50:28 更新,目前是第 2 版。