perl简要教程
时间:2006-03-28 来源:EricssonXiao
第一课、Perl 概述 |
|
|
Perl是Practical Extraction and Report Language(实用摘录和报告语言)的简称,是由Larry Wall所发展的。其最新版本为5.0。 |
第二课、Perl 变量(1)--纯变量
Perl有三种变量:
- 纯变量(Scalar Varible)
- 数组(Array)
- 关联数组(Associative array)
又称标量变量,是Perl处理的最简单的数据类型。标量可以是数字(如2,3或2.5e6),也可以是字符串(如“hello”和“网易”)。
Perl中的标量变量以美元符号$和一个字母开始,以后可以是字母、数字和下划线,大小写有区别,而且所有字母、数字和下划线都有效。如:
$a和$A是不同的变量;
$this_is_a_long_variable_1和
$this_is_a_long_variable_2是不同的变量;
Perl中的变量可以通过操作符(如+或.等)来产生新的变量。你可以从文件和设备中读取变量,也可以将其输出。
使用纯量变量时要在前面加上$符号, 注意:指定的纯变量是一个字符的话,就要加上""双引号或单引号;如果是数值的话,就不用加上""这个符号。
标量数据又可以分为数字和字符串两种:
数字
可分为整型变量和浮点变量。
整型变量:(如2,-200,3568等)。Perl支持8进制和16进制变量,8进制以0开头(如0255,表示8进制的255),16进制以0x或0X开头 (如-0x1a,代表负的1A)
实型变量:(如2.5,-6.3e5,-2.3-e6等)。
字符串
最短的字符串可以没字符,最长可以把你的内存填满,这与Perl的“无内置限制”的原则一致。
字符串有两种格式:单引字符串和双引字符串。
单引字符串(single-quoted string): 就是用单引号括起来的一串字符。该单引字符串不是字符串的一部分。引号中可以插入任何字符。只有两种情况例外,一种是中间插入单引号,并在前面有一反斜杠;一种是字符串有两个连着的反斜杠。
双引字符串(double-quoted string): 就是用双引号括起来的一串字符,其作用类似于C语言。
双引字符串中反斜杠转义表
结 构 |
含 义 |
\n |
换行 |
\r |
回车 |
\t |
水平置表符 |
\f |
换页符 |
\b |
退格 |
\v |
垂直置表符 |
\a |
响铃 |
\e |
Esc |
\007 |
任一八进制ASCII值(这里007表示bell) |
\x7f |
任一十六进制ASCII值 |
\cC |
任一“控制”字符 |
\\ |
反斜杠 |
\" |
双引号 |
\l |
下一字母小写 |
\L |
以后所有字母小写直到\E |
\u |
下一字母大写 |
\U |
以后所有字母大写直到\E |
\E |
结束\L和\U |
标量变量的运算符
1、赋值运算符
如:$a=23; #将23赋值给$a
$b=$a=23; #将23赋值给$a和$b
$b=3+($a=2); #将2赋值给$a,再加3将值赋给$b,即$b为5
2、二元赋值运算符
如:$a=+3; #等同于$a=$a+3
这与C语言中基本相同。
3、自增自减运算符
如:$a++; #等同于$a=$a+1
这与C语言中基本相同。
4、chop()运算符
如:$a="hello";
chop($a); #此时$a的值为"hell"。
这对于从屏幕获取文本后去除换行符很有用。
如:$a=<STDIN>; #获取文本
chop($a); #去除最后的换行符。
这两行可合并为:
chop($a=<STDIN>);
5、字符串的标量插入值
如:$a="zmd";
$b="hello! $a";
$b的值为"hello! zmd"。
综合示例
$url1='hello'; |
#将hello这串字符赋给$url1变量; |
$url2='don\'t'; |
#将don't这串字符赋给$url2变量; |
$url3='hello\n'; |
#将hello\n这串字符赋给$url3变量;注意\n不被当作换行符而是\和n两个字符; |
$url1="http://zmd.zb169.net"; |
#将http://zmd.zb169.net这串字符赋给$url1变量; |
$url2="/cgi-bin/"; |
#将/cgi-bin/这个字符赋给$url2变量; |
$url3=$url1.$url2; |
#将两个变量的字符串连起, |
$int=5; |
#将10赋给$int变量; |
$int=5+6; |
#$int=11; |
$int=5*6; |
#$int=30; |
$int=5;$int++; |
#$int=6; |
$int=5;$int+=8; |
#$int=13; |
$a="\Uzmd";$b="\u\LZHENG";$c="$a $b" |
#$a="ZMD"; $b="Zheng"; |
第三课、Perl 变量(2)--数组
数组是标量数据的有序列表。 数组可以含任意多个元素。最小的数组可以不含元素,而最大的数组可以占满全部可用内存。
数组实量(array literal)是位于括号内用逗号分开的一系列值。如:
数组变量具有单独的数组值,要以@打头而不是$。如:
数组的赋值和标量赋值一样,也用等号表示。Perl根据赋值对象是标量还是数组变量来确定赋值操作是标量赋值还是数组赋值。
数组元素的访问和C语言中类似,下标是按顺序整数排列的,编号从0开始。 综合举例
|
第四课、Perl 变量(3)--关联数组
关联数组和前面说的数组类似,它包含标量数据,可用索引值来单独选择这些数据,和数组不同的是, 关联数组的索引值不是非负的整数而是任意的标量。这些标量称为Keys,可以在以后用于检索数组中的数值。 %ARRAY=(key1,value1,key2,value2,key3,value3); 每一个key都有一个相对应的值(value)。 和数组类似,$zmd,@zmd,%zmd之间没有任何联系。Perl为对象的不同类型保留独立的命名空间。 下面介绍关联数组的操作:
关联数组的综合举例:
|
第五课、Perl的运算符号字符 |
||
赋值(Assignment)运算符 |
||
符号 |
范例 |
说明 |
= |
$x=$y; |
将$x的值指派给$y |
+= |
$x+=$y; |
将$x加$y之后再指派给$x |
-= |
$x-=$y; |
将$x减$y之后再指派给$x |
*= |
$x*=$y; |
将$x乘$y之后再指派给$x |
/= |
$x/=$y; |
求出$x除以$y之后的商数,再指派给$x |
**= |
$x**=$y; |
将$x乘上$y次方之后再指派给$x |
%= |
$x%=$y; |
求出$x除以$y的余数以后,再指派给$x |
.= |
$str1.=$str2; |
将$str1这个字符串再加上$str2这个字符串之后,再指派给$str1这个字符串 |
x= |
$strx=$y; |
重复$str字符串$y次,并反结果指派给str这个字符串 |
符号 |
范例 |
说明 |
+ |
$z=$x+$y |
将$x和$y相加之后,再将结果指派给$z |
- |
$z=$x-$y |
将$x减掉$y之后,再将结果指派给$z |
* |
$z=$x*$y |
将$x和$y相乘之后,再将结果指派给$z |
/ |
$z=$x/$y |
将$x除以$y之后,再将商数指派给$z |
% |
$z=$x%$y |
将$x除以$y之后,再将余数指派给$z |
** |
$z=$x**$y |
将$x乘以$y之后,再将结果指派给$z |
++ |
$x++;++$x; |
如同$x=$x++1;将$x加一以后再将结果指派给$x |
-- |
$x--;--$x; |
如同$x=$x-1;将$x减一以后再将结果指派给$x |
. |
$z=$x.$y; |
将$x字符串和$y字符串连接之后,再将结果指派给$z |
符号 |
范例 |
说明 |
> |
$x>$y |
如果$x大于$y,返回1的值,否则返回0 |
>= |
$x>=$y |
如果$x大于等于$y,返回1的值,否则返回0 |
< |
$x<$y |
如果$x小于$y,返回1的值,否则返回0 |
<= |
$x<=$y |
如果$x小于等于$y,返回1的值,否则返回0 |
== |
$x==$y |
如果$x等于$y,返回1的值,否则返回0 |
!= |
$x!=$y |
如果$x不等于$y,返回1的值,否则返回0 |
<=> |
$x<=>$y |
如果$x大于$y,返回1的值,如果$x等于$y,否则返回0;&127;如果 $x小于$y,则返回-1的值 |
符号 |
范例 |
说明 |
gt |
$str1 gt $str2 |
如果$str1大于$str2,返回1的值,否则返回0 |
ge |
$str1 ge $str2 |
如果$str1大于等于$str2,返回1的值,否则返回0 |
lt |
$str1 lt $str2 |
如果$str1小于$str2,返回1的值,否则返回0 |
le |
$str1 le $str2 |
如果$str1小于等于$str2,返回1的值,否则返回0 |
eq |
$str1 ep $str2 |
如果$str1等于$str2,返回1的值,否则返回0 |
ne |
$str1 ne $str2 |
如果$str1不等于$str2,返回1的值,否则返回0 |
cmp |
$str1 cmp $str2 |
如果$str1大于$str2,返回1的值,如果$str1等于$str2,返回0,如果$str1小于$str2,则返回-1的值 |
1 $x&&$y(And) $x $y 结果 真(True) 真(True) 真(True) 真(True) 假(False) 真(True) 假(False) 真(True) 假(False) 假(False) 假(False) 假(False) 2 $x||$y(Or) $x $y 结果 真(True) 真(True) 真(True) 真(True) 假(False) 真(True) 假(False) 真(True) 真(True) 假(False) 假(False) 假(False) 3 $x(Not) $x 结果 真(True) 假(False)假(False) 真(True) |
||
指令:..区块运算符(Range Operator) 说明:这个运算符是Perl语言中特有的运算符,是一个很实用的运算符. 范例:
@digits=(1..9); #此时@digits=(1,2,3,4,5,6,7,8,9); 指令: 判别运算式?运算1:运算式2 条件运算符(Conditional Operator) 说明: 这个语法的意义和C语言一样,如果判别运算式的值是真(True)的话,则做运算 ,1的运算,如果判别运算式是假(False)的话,则做运算式2的运算. 范例:
$price=($age>60)? 100:200; |
||
范例 |
说明 |
|
-r $file |
如果$file是可读取的话,返回1的值 |
|
-w $file |
如果$file是可写入的话,返回1的值 |
|
-x $file |
如果$file是可执行的话,返回1的值 |
|
-e $file |
如果$file存在的话,返回1的值 |
|
-o $file |
如果$file是被执行才所拥有的话,返回1的值 |
|
-s $file |
返回$file的文件大小(bytes) |
|
-f $file |
如果$file是正常文件的话,返回1的值 |
|
-T $file |
如果$file是文本文件的话,返回1的值 |
|
-B $file |
如果$file是Binary文件的话,返回1的值 |
|
-M $file |
返回$file文件最后一次更改时间到现在的日期数 |
第六课、Perl的基本输入输出 从STDIN输入 |
从标准输入设备读取数据是很容易的,我们已经从第一课上就使用<STDIN>操作符了。例如: |
第七课、控制结构(1)-判断控制
选择性控制结构
选择性控制结构包括if和unless语句,类似于C语言中的if。
首先介绍一下真和假的定义。在Perl中,这些规则有些难以理解。控制表达式的值为空串或0时,则表达式为假,对于其它任何情况,表达式的值都为真。
注意:"00"不是空串或0,值为真。"0.0"也是如此。
指令: if 假如
语法一:
if(判别运算式)
{
表达式为真时的语句块;
}
上个语法在Perl中也可以写成:
表达式为真时的语句块 if (判别运算式);
范例:
print"请输入您的分数?\n";
$scorre=<STDIN>; #<STDIN>代表标准输入,会让使用者输入一字符串
chop($score); #将$score最后一个换行字符\n删除掉
if($score>=60){
print"您的分数及格了!\n";
}
也可以写成: print "您的分数及格了!\n" if ($score>=60);
语法二:
if(判别运算式一){
判别式一为真时的语句块;
}else{
判别式一为假时的语句块;
}
范例:
print"请输入您的分数?\n";
$scorre=<STDIN>;
chop($score);
if($score>=60)
{
print"您的分数及格了!\n";
}else{
print"您的分数不及格!\n";
}
语法三:
if (判别运算式一)
{
判别式一为真时的语句块;
}elsif(判别运算式二){
判别式二为真时的语句块;
}elsif(判别运算式三){
判别式三为真时的语句块;
}else{
所有判别式为假时的语句块;
}
范例:
print"请输入您的分数?\n";
$scorre=<STDIN>;
chop($score);
if($score>60)
{
print"您的分数大于60分!\n";
}elsif ($score<60){
print"您的分数小于60分!\n":
}else{
print"您的分数刚好是60分!\n";
}
指令: unless 假如非
unless的含义就是说“如果判别式不为真,就执行...”。
语法一:
unless(判别运算式) {
判别式为假时语句块;
}
上个语法在Perl中也可以写成:判别式为假时语句块 unless (判别运算式);
范例:
print"请输入您的分数?\n";
$scorre=<STDIN>; #<STDIN>代表标准输入,会让使用者输入一字符串
chop($score); #将$score最后一个换行字符\n删除掉
unless($score<60)
{
print"您的分数及格了!\n";
}
也可以写成: print"您的分数及格了!\n"unless($score<60);
语法二:
unless(判别运算式)
{
判别式为假时语句块;
}else{
判别式为真时语句块;
}
范例:
print"请输入您的分数?\n";
$scorre=<STDIN>;
chop($score);
unless($score<60)
{
print"您的分数及格了!\n";
}else{
print"您的分数不及格!\n";
}
进阶技巧:&&,||及?:作为控制结构
它们看上去像标点符号,或是表达式的一部分。但在Perl中可作为控制结构。
比如说:
if (判别表达式)
{为真时语句块};
也可以写为:
为真时的语句块 if (判别表达式)
但更简单的方式是:
判别式 && 为真时的语句块
为什么呢?&&为逻辑与操作符,其含义为:
若判别式为真,则表达式的值依赖于后面语句块的值。所以为真时的语句块被执行(用来求值)。
若判别式为假,则整个表达式为假,不用考虑后面语句块的值。所以为假时的语句块不被执行。
同样道理,unless(this){that}可替换为this||that。
?:表达式举例:exp1?exp2:exp3表示:如果exp1为真则求exp2的值,否则求exp3的值。
第八课、控制结构(2)-循环控制
循环性控制结构
任何一种语言没有循环就是不完整的。Perl也是如此,它可以用while, do...while, for, until, foreach来实现。
循环中还可以用last,next,redo等操作符进行控制。
指令:
while 当..
语法:
while(判别运算式) {
程序叙述区块;
}
上个语法在Perl中也可以写成: 程序叙述区块while(判别运算式);
范例一:
while($<=10)
{
$sum+=$i;
$i++;
}
print"$sum\n"; #此时$sum =55;
范例二:
$filename="/path/cgi.txt";
open(FILE,"$filename")||die "Cannot open $filename\n";
#可以把<FILE>视为打开文件某一行的数据
while($line=<FILE>)
{
print "$line";
}
close(FILE);
就会把cgi.txt这个文件的内容显示出来。
而这个范例可以把它改写成:
$filename="/path/cgi.txt";
open(FILE,"$filename")||die "Cannot open $ filename\n";
print "$line"while($line=<FILE>);
close (FILE);
在这个范例中是把$filename文件内的数据一行一行的指派给$line这个纯量变量,再把$line显示出来.如果没有将<FILE>指派给一个纯量变量的话,则会有一内定的输入变量$_被<FILE>所指派.因为$_是一个内定的变量,所以如果使用print函数的时候没有加上要输出数据的话,就会把$_的数据print出来.所以这个范例也可以改写成: $filename="/path/cgi.txt";
open(FILE,"$filename")Ⅱdie"Cannot open $ filename\n";
while(<FILE>)
{
print;
}
close(FILE);
指令:
do while 当..
语法:
do
{
程序叙述区块;
}while(判别运算式);
在while和do while循环中最大的不同是在do while循环中,程序叙述区块至少会被执行一次。
范例:
do{
$sum+=$i;
$i++;
}while($i<=10);
print "$sum\n"; #此时$sum=55;
指令:
until 直到...才
语法: until(判别运算式)
{
程序叙述区块;
}
上个语法在Perl中也可以写成: 程序叙述区块 until (判别运算式);
范例:
until($i>10){
$sum+=$i;
$i++;
}
print "$sum\n"; #此时$Sum=55;
指令:
do while 直到...才
语法:
do{
程序叙述区块;
}until (判别运算式);
范例:
do{
$sum+=$i;
$i++;
}until($i>10);
print "$sum\n"; #此时$sum=55;
指令:
for 循环陈述
语法一:
for (初始化运算式;判别运算式;循环过程运算式)
{
程序叙述区块;
}
范例一:
$sum=0;
for($i=1;$i<=10;$i++)
{
$sum+=$i;
}
print "$sum\n"; #此时$sum=55;
范例二:
@array=(3,6,9);
$number=@array; #把数组@array的元素个数指派给$number
#此时$number=3;
for($i=0;$inumber;$i++)
{
$sum+=$array[$i]; #把数组@array元素的值全部加起来
}
print"$sum\n"; #此时$sum=18;
语法二:
for $ variable(@array)
{
程序叙述区块;
}
在Perl语言中的for循环陈述还可以使用这个语法,各循环陈述foreach的用法一样.如果把$variable变量省略的话,就会将数组@array的元素一个一个指定给$_这个变量,这是比较精简的写法.
范例:
@array=(3,6,9);
for $int(@array)
{
$sum+=$int;
}
print"$sum\n"; #此时$sum=18;
也可以写成:
@array=(3,6,9);
for (@array)
{
$sum+=$_;
}
print"$sum\n"; #此时$sum=18;
指令:
foreach 循环陈述
语法:
foreach $ variable(@array)
{
程序叙述区块;
}
如果把$variable变量省略的话,就会将数组@array的元素一一指定给$_这个内定的输出变量.
范例一:
@array=(3,6,9);
foreach $int(@array)
{
$sum+=$int;
}
print "$sum\n"; #此时$sum=18;
也可以定成:
@array=(3,6,9);
foreach(@array)
{
$sum+=$_;
}
print "$sum\n"; #此时$sum=18;
范例二:
%FORM=("name","NCTU","value","TEM");
foreach $pair(sort keys%FORM)
{
print "$pair is $FORM{pair}\n";
}
这个范例在CGI语言写作中常常会用到.先用keys喧个函数来求出关联数组中全部的key,再用sort这个函数把全部的key由小到大排序,最后再把关联数组中的key和所对应的值(value)一一显示出来.而以上这个程序也可写成:
%FORM=("name","NCTU","value","TEM");
@array=(sort keys%FORM);
foreach $pair(@array)
{
print "$pair is $FORM{pair}\n";
}
指令:
last 退出循环陈述
语法:
last
范例:
for($i=1;$i<=10;$i++)
{
last if ($i==5); #如果$i等于5的话就退出for循环
print"$i\n";
}
会把1到4之间的数值显示出来.
指令:next 到循环的下一个陈述
语法:next
范例:
for($i<=10;$i++)
{
#如果是2的倍数的话,就到循环的下一个陈述
next if($i%2)==0)
print"$i是一个奇数!\n";
}
会把1以10之间的奇数显示出来。
第九课、常规表达式(1)
如果在Unix中曾经使用过sde,awk,grep这些指令的话,相信对于 Perl 语言中的常规表达式(Regular Expression)应该不会感到陌生才对。在Perl语言中因为有这个功能,所以对于字符串的处理能力是非常强有力的。Regular Expression可视为用来处理字符串的一种模式(pattern),其使用的格式为/pattern/。在Perl语言的程序中,经常可以看到类似语法的应用,在CGI程序设计中也不例外。只要能够善用常规表达式的话,要处理任何难的字符串皆可迎刃而解,在本章中笔者会用深入浅出的方式来介绍Regular Expression的用法。
常规表达式(Regular Expression)也译作正则表达式或文字处理模式,是指定模式的一种方法,这种模式对文本进行筛选,只匹配特定的字符串。一旦匹配到了一个字符串,就可以从大量的文本中将其抽取出来,或者利用另一个字符串来替代这个字符串。
常规表达式也是初学Perl者的难点所在,但一旦掌握其语法,它们就拥有几乎无限的模式匹配能力,而且Perl编程的大部分工作都是掌握常规表达式。
一 常规表达式中,/pattern/常用到的语法
/pattern/ |
结果 |
|
除了换行字符\n外,找寻只有一个字符的字符串 |
x? |
找寻0个或是1个x字符 |
x* |
找寻0个或是0个以上的x字符 |
.* |
找寻0个或是0个以上的任何字符 |
x+ |
找寻0个或是1个以上的x字符 |
.+ |
找寻1个或是1个以上的任何字符 |
{m} |
找寻刚好是m个个数指定的字符 |
{m,n} |
找寻在m个数个数以上,n个个数以下指定的字符 |
{m,} |
找寻m个个数以上指定的字符 |
[] |
找寻符合[]内的字符 |
[^] |
找寻不符合[]内的字符 |
[0-9] |
找寻符合0到9的任何一个字符 |
[a-z] |
找寻符合a到z的任何一个字符 |
[^0-9] |
找寻不符合0到9的任何一个字符 |
[^a-z] |
找寻不符合a到z的任何一个字符 |
^ |
找寻字符开头的字符 |
$ |
找寻字符结尾的字符 |
\d |
找寻一个digit(数字)的字符,和[0-9]语法一样 |
\d+ |
找寻一个digit(数字)以上的字符串,和[0-9]+语法一样 |
\D |
找寻一个non-digit(非数字)的字符,和[^0-9]语法一样 |
\D+ |
找寻一个non-digit(非数字)以上的字符,和[^0-9]+语法一样 |
\w |
找寻一个英文字母或是数值的字符,和[a-zA-Z0-9]语法一样 |
\w+ |
找寻一个以上英文字母或是数值的字符,和[a-zA-Z0-9]+语法一样 |
\W |
找寻一个非英文字母,数值的字符,和[^a-zA-Z0-9]语法一样 |
\W+ |
找寻一个以上非英文字母,数值的字符,和[^a-zA-Z0-9]+语法一样 |
\s |
找寻一个空白的字符,和[\n\t\r\f]一样 |
\s+ |
找寻一个以上空白的字符,和[\n\t\r\f]+一样 |
\S |
找寻一个非空白的字符,和[^\n\t\r\f]一样 |
\S+ |
找寻一个以上非空白的字符,和[^\n\t\r\f]+一样 |
\b |
找寻一个不以英文字母,数值为边界的字符串 |
\B |
找寻一个以英文字母,数值为边界的字符串 |
a|b|c |
找到符合a字符或是b字符或是c字符的字符串 |
abc |
找到一个含有abc的字符串 |
(pattern) |
()这个符号是会记忆所找寻到的字符,是一个很实用的语法 |
/pattern/i |
i这个参数是代表忽略英文大小写的意思,也就是在找寻字符 串的时候,不会去考虑英文的大小写 |
\ |
如果要在pattern模式中找寻一个有特殊的意义的字符,要在 这个字符前加上\这个符号,这样才会让这个特殊字符失效 |
|
二 常规表达式(Regular Expression)的简单范例
看了上一小节文字处理模(Regular Expression)之的,初学者对于这个语法的应用可能还不是很清楚,所以笔者会在这一小节中,举出一些在常规表达式中常用的范例给大家看看:
范例 |
说明 |
/perl/ |
找到含有perl的字符串 |
/^perl/ |
找到开头是perl的字符串 |
/perl$/ |
找到结尾是perl的字符串 |
/c|g|i/ |
找到含有c或g或i的字符串 |
/cg{2,4}i/ |
找到c后面跟着2个到4个g,再跟着i的字符串 |
/cg{2,}i/ |
找到c后面跟着2个以上g,再跟着i的字符串 |
/cg{2}i/ |
找到c后面跟着2个g,再跟着i的字符串 |
/cg*i/ |
找到c后面跟着0个或多个g,再跟着i的字符串,如同/cg{0,1}i/ |
/cg+i/ |
找到c后面跟着一个以上g,再跟着c的字符串,如同/cg{1,}i/ |
/cg?i/ |
找到c后面跟着0个或是一个g,再跟着c的字符串,如同/cg{0,1}i/ |
/c.i/ |
找到c后面跟着一个任意字符,再跟着i的字符串 |
/c..i/ |
找到c后面跟着二个任意字符,再跟着i的字符串 |
/[cgi]/ |
找到符合有这三个字符任意一个的字符串 |
/[^cgi]/ |
找到没有这三个字符中任意一个的字符串 |
/\d/ |
找寻符合数值的字符串 |
/\D/ |
找寻符合不是数值的字符串 |
/\w/ |
找寻符合英文字母,数值的字符串 |
/\W/ |
找寻符合非英文字母,数值字符的字符串 |
/\s/ |
找寻符合空白的字符串 |
/\S/ |
找寻符合不是空白的字符串 |
/\*/ |
找寻符合*这个符号的字符串,因为*在常规表达式中有它的特殊意思,所以要在这个特殊符号前加上\这个符号,这样才会让这个特殊字符失效 |
/abc/i |
找寻符合abc的字符串而且不考虑这些符合字符串的大小写 |
第十课、常规表达式(2)
三 常规表达式(Regular Expresion)相关的运算符及函数
在perl程序写作中常会用到=~和!~这两个运算符及s和t这二个函数来和常规表达式/pattern/搭配而成一个运算式,如果能够活用这些指令的话,就可以很。轻易地来处理一些字符串,当然在CGI程序设计中了就更能得心应手了。现在就让作者来介绍这些运算符及函数的用法:
指令:/pattern/文字运算
说明: 如果在文字运算中没有使用=~或是!~运算符指定一个字符串来做运算的话,就会使用内定的输出变量$_来做/pattern/文字运算。
范例一:
$string="chmod711cgi";
$string=~/(\W)\s+(\d+)/;
第一个(\W+)是代表找寻数个字母,并将的找到的字符串指派给$1这个变量,而\s+代表找寻多个空白的字符串,最后(\d+)代表找寻个数值,并将所找到的字符串指派给$2这个变量。所以$1="chmod";$2=711;但是$string还是等于原来的字符串,没有改变。
范例二:
$_="chmod711cgi";
/(\W)\s+(\d+)/;
因为是把字符串指定给$_这个变量,所以可以不用=~这个运算符就会得到
$1="chmod";$2=711;而且$_还是等于原来的字符串,没有改变。
范例三:
$string="chmod711cgi";
@list=split(/s+/,$string);
以上一个或是多个空白字符来分割$string这个字符串,这是一个很常用的语法。此时@list=("chmod","711","cgi");
指令: =~相配运算符
说明:这是Perl语言中特有的语法,通常会和文字处理来作运算。
范例:
print"请输入一个字符串!\n";
$string=<STDIN>; #<STIDN>代表标准输入,会让使用者输入一字符串
chop($string); #将$string最后一个换行的字符\n删除掉
if($string=~/cgi/){
print("输入的字符串中有cgi这个字符串!\n";
}
如果输入的字符串含有cgi这个字符串的话,就会显示出这个信息。
指令:!~不相配运算符
说明:这也是Perl语言中特有的语法,通常会和常规表达式来运算。
范例:
print"请输入一个字符串!\n";
$string=<STDIN>; #<STIDN>代表标准输入,会让使用者输入一字符串
chop($string); #将$string最后一个换行的字符\n删除掉
if($string!~/cgi/)
{
print("输入的字符串中有cgi这个字符串!\n";
}
如果输入的字符串中没有cgi这个字符串的话,就会显示出这个信息。
指令:tr转换函数
语法:tr/SEARCHLIST/REPLACELIST/
其中SEARCHLIST是要转换的字符;REPLACELIST是转换成何种字符。
说明:tr(translate)就是转换的意思,会把符合转换的字符转换成要转换的字符。
范例一:
$string="testing";
$string=~tr/et/ET/"; #此时$string="TEsTing";
$string=~tr/a-z/A-Z/; #此时$stirng="TESTING";
范例二:
$string="CGI+Perl";
$string=~tr/+//; #此时$string="CGI Perl";
在传送CGI数据的时候会先将数据编码,其中会将空白的字符转成+这个字符。
指令:s 取代函数
语法:s/PATTERN/REPLACE/eg
其中
- PATTERN是文字处理(Regular Expresion)的模式;
- REPLACE是代表取代成何种文字模式。
- 而g是这个函数最常用的参数,代表要把所有符合文字模式的字符串全部取代,如果省略这个参数的话,则只取代一个符合文字模式的字符串中;
- 而加上e这个参数代表要将REPLACE的部分当成一个运算式,如果没有这个需要的话,就不用加上这个参数了。
说明:将符合常规表达式的字符串取成为要取代的字符串
范例一:
$string="i:love:perl";
$string=~s/:/*/; #此时$string="i*love:perl";
$string=~s/:/*/g; #此时$string="i*love*perl";
$string=~s/*/+/g; #此时$string="i+love+perl";
$string=~s/+//g; #此时$string="i love perl";
上一行也可写成 $string=~tr/+//;效果都会一样哦!
$string=~s/perl/cgi; #此时$string="i love cgi";
范例二:
$string=~s/(love)/<$1>/;
第一个()内所找到的字符串变成$1,在这个范例中,会把变量love这个字符串变成<love>,此时$string="i<love>perl";
$string="i love perl";
$string=~s(i)(perl)/<$1><$2>/;
在这个范例中,会把i变成<i>;perl变成<perl>,此时$string="<perl> love <i>";
$string="i love perl";
$string=~s(\W+)/<$1>/g;
(/w+)代表找寻符合一个或是多个英文字符或是数值的字符串,之后再将找到的字符串设成$1。因为加上g这个参数,所以会找到字符串的这三个英文单字,然后再把这三个单字分加上<>这个符号,此时$string="<perl><love><i>";
范例三:
$string="www22cgi44";
$string=~s/(\d+)/$1*2/e;
(/d+)代表要找寻$string中一个或是多个数值的字符串,再将找到的字符串设成$1。加上参数e是代表要把$1*2当作是一个运算式,所以$string="www22cgi44";
$string="www22cgi44";
$string=~s/(\d+)/$1*2/eg;
加上参数e,所以会把$1*2当作是一个运算符式来看;加上参数g就会把全部符合数值的字符串经过运算式运算之后再把它取代,所以$string="www44cgi88";
范例四:
假设原本的字符串是$value="三八!",经CGI数据编码之后,这个字符串就会变成
$value="%A4T%A4K%21"。以下是一个解码的示范程序:
$value="%A4T%A4K%21";
$vlaue=~s/%([a-fA-F0-9][a-fA-F0-9]/pack("c",hex($1))/eg;
在传送CGI数据的时候会把数据编码,其中会将特殊字符或是中文字符编码以%开头的连续的两个十六进制数的字符串,所以要用s这个函数来找寻这个以%开头的字符串。为了要把找到的字符串再做解码的处理,所以要在%这个符号之后加上()这个符号,表示会把找到的字符串记忆起来并指定给$1这个变量,而且要在()中加上代表是连续两个十六进制数值的常规表达式(Regular Expression),也就是[a-fA-F0-9][a-fA-F0-9]。再用hex这个函数($1是代表符合的字符串)把十六进制数值转成十进制的码,之后再用pack这个函数(以C为参数,是代表unsigned char value的意思)把这个十进制码还原成原来的字符串。最后就会把这个字符串解码成$value="三八!"。值得一提的是也可以把这个解码的程序写成:
$value=~s/%(..)/pack("C",hex($1))/eg;
在此提供给读者参考。
第十一课、函数(1)--用户自定义函数(子程序)
函数可分为系统函数和用户函数。
用户函数
用户函数又称子程序(Subroutine),在Perl中用下面的结构来定义用户函数:
sub 子程序名{
语句块;
}
这里的子程序名与变量的取名规则类似。
以显示欢迎词的程序为例:
sub say_hello{
print "你好,欢迎光临网上学园";
}
用户函数的定义可以位于程序的任何位置,比如说放在文件的未尾。如果两个子程序使用了相同的程序名, 后面的子程序将覆盖前面子程序。
用户函数中的变量默认为全局变量,与其他程序共享。
用户函数的调用:通过在子程序前加“&”调用,可在任一表达式内调用。 子程序中可以再调用另外的子程序。
调用用户函数产生的结果称为返回值(return value)。返回值是每次调用函数中最后一个表达式的计算值。以加法函数为例:
sub add_a_b{
$a+$b;
}
函数最后一条表达式为$a+$b,故返回值为$a+$b。以下是调用情况:
$a=5;
$b=6;
$c=&add_a_b; #$c的值为11
$d=5*&add_a_b; #$d的值为5*11即55
上述的函数功能与传统直接写在程序中没什么两样,如果加上参数传递就可以实现全新的功能了。 在Perl中,如果函数调用后面跟着一个用括号括起来的列表,则在函数调用期间该列表将被自动分配给以@_命名的特殊变量。 函数可以访问该变量,从而确定参数的个数及赋值。
仍以加法函数为例:
sub add_a_b{
$_[0]+$_[1];
}
$c=&add_a_b(5,6); #$c的值为11
$d=5*&add_a_b(2,3); #d的值为5*5即25
如何改变参数的个数呢?我们可以用循环的方式来实现:
sub add_all{
$sum=0; #将sum初始化
foreach $_(@_) { #遍历参数列表
$sum+=$_; #累加每个元素
}
$sum; #返回sum即总和的值
}
$a=&add_all(3,4,5); #$a的值为3+4+5即12
$d=2*&add_all(1,2,3,4,5); #d的值为2*15即30
既然函数中的变量全为全程变量,那么上述程序中若调用程序中含有$sum变量时将替换,这不是我们所要的。那么如何解决这一问题呢?
答案就是:使用局部变量, 使用local()操作符就可实现此功能。在上面的程序中,只需在第一行$sum=0;前加入:
local($sum);
当函数执行时,$sum的全程变量的值被保留起来,同时建立一个局部变量$sum,退出函数add_all后将全程变量$sum的值恢复。如:
sub add_all{
local($sum); #将$sum定义为局部变量
$sum=0; #将sum初始化
foreach $_(@_) { #遍历参数列表
$sum+=$_; #累加每个元素
}
$sum; #返回sum即总和的值
}
$sum=88; #$sum的原始值为88
print $sum; #显示$sum的值即88
$a=&add_all(3,4,5); #$a的值为3+4+5即12
print $sum; #显示$sum的值仍为88
比较:若未加入local($sum);行,最后一行的执行结果将为12。
下面再举一例:计算十以内的加法,并以中文形式输出。当超过十时输出阿拉伯数字。如:输入两个数字,显示“一加二等于三”。程序如下:
#/! /usr/bin/perl
sub cnumber{
@chinese=("0","一","二","三","四","五","六","七","八","九");
#将@chinese定义为数组
local($number); #将number定义为局部变量
$chinese($number)||number; #想想为什么?
}
#主程序
print "请输入一个数:"
chop($num1=);
print "请再输入一个数:"
chop($num2=);
$msg=&chinese($num1)."加".&chinese($num2)."等于".
&chinese($num1+num2)."。\n"
print $msg; #打印$msg的值
其中$chinese($number)||number; 行的初级写法为:
if ($chinese(number) {
&chinese($number); #返回中文
} else {
&number; #返回阿拉伯数字
}
看看执行结果:输入2,3,显示:"二加三等于五。";输入3,12,显示:"三加12等于15。"
。
第十三课、文件及目录操作
大多数程序都不是孤立的,它们与它们的环境相互作用。很多的程序也需要通过文件操作实现数据的存贮和交换。 文件句柄(file handle)是Perl程序中为程序和外部世界提供I/O连接的名称。建议全部使用大写字母以示与变量等的区别。特别地,也可以将STDIN/STDOUT/STDERR也认为 是Perl的文件句柄,分别代表标准输入/标准输出/标准错误输出。
打开及关闭文件
Perl的文件操作与C语言极为相似。如:
open(FILENAME,"abc.txt");
该调用为读文件打开,若为写文件而打开,需在文件名前加上大于号:
open(FILENAME,">abc.txt");
若要追加至文件尾,可在文件名前加上两个大于号:
open(FILENAME,">>abc.txt");
以上三种open()格式在成功时返回真,失败时返回假。但程序中通常没有提示,出错时往往会被人们忽略。通常当需要给出出错提示时,可加入die()函数。例:
open(OUTFILE,">/tmp/outfile")||
die "出错,不能建立/tmp/outfile\n";
当只有open失败时,才会执行die给出出错提示。
对文件句柄的操作完成后,可以用close操作符关闭文件。如:
close(OUTFILE);
-x 文件测试
Perl的文件操作也可以先测试文件是否存在,是否可读写等。如:
$x="abc.txt";
if(-e $x) { #abc.txt是否存在?
# 存在操作
} else {
printf "文件不存在。\n";
}
-e操作符测试文件或目录是否存在。
以下为文件测试清单:
文件测试 |
测试操作符提供的信息 |
-r |
文件或目录可读 |
-w |
文件或目录可写 |
-x |
文件或目录执行 |
-o |
文件或目录归用户所有 |
-R |
文件或目录对真正用户可读 |
-W |
文件或目录对真正用户可写 |
-X |
文件或目录对真正用户执行 |
-O |
文件或目录归真正用户所有 |
-e |
文件或目录存在 |
-z |
文件存在且大小为0 |
-s |
文件或目录存在且不为0(返回字节数) |
-f |
文件为普通文件 |
-d |
文件为目录 |
-l |
文件为符号链接 |
-p |
文件为命名管道(FIFO) |
-S |
文件为一个套口(socket) |
-b |
文件为块特殊文件 |
-c |
文件为字符特殊文件 |
-t |
打开tty控制台的文件句柄 |
-u |
文件或目录是设置用户ID号 |
-g |
文件或目录是设置用户组ID号 |
-k |
文件或目录的sticky位置位 |
-T |
文件是文本文件 |
-B |
文件是二进制文件 |
-M |
以天为单位的存在时间 |
-A |
以天为单位访问时间 |
-C |
以天为单位同代码更改时间 |
|
删除文件
Perl的unlink()操作符可实现删除文件。如:
unlink("abc.txt"); #删除abc.txt
文件重命名
Perl的rename()操作符可实现文件重命名。如:
rename("abc","zmd")||die "出错,不能更名";
此时将abc更名为zmd,成功返回真,否则给出出错提示。
目录操作
Perl中处理目录非常类似于处理文件。
打开目录句柄:
opendir(ETC,"/etc")||die "出错,不能打开目录";
关闭目录句柄:
closedir(ETC);
创建目录:
mkdir("zmd",0777)||die "不能创建zmd目录";
0777为内部权限格式。
删除目录:
rmdir("zmd")||die "不能删除zmd目录"。
第十四课、进程管理
当你向系统shell发送一个命令行时,shell创建一个进程来执行这个命令。这个新进程成为shell的子进程,它的执行不依赖于shell但又与shell相互协调。
同样,Perl程序也能启动新进程。
使用system()和exec()
生成新进程的最简单的方法就是用system操作符。如:
system("date");
若要将输出送至now_day文件,则可以:
system("date>now_day") ||die "不能建立now_day文件";
使用单引号
产生进程的另一方法是将shell命令置于两个单引号之间。如:
$nowday="现在时间:".'date'
$nowday的值为“现在时间:”和date命令的结果的连接。即:"现在时间:Fri Feb 18 23:49:23 PDT 1998"
综合范例
举一个综合例子,要求从date的输入中分析,周未时打印"周未了,别太辛苦",否则打印"好好工作"。简洁的写法为:
if('date'=~/^S/){
printf "网上学园欢迎您,周未了,别太辛苦";
} else {
printf "好好工作\n"
}
date的输出格式第一个字节为星期,英语中恰好只有周未为"S"打头,因此使用了常规表达式判断第一个字符是否为S,即可达到要求。