《Learning Perl》学习笔记 教程
第一章 简介
写在前面:
本着读书“由厚变薄,再由薄变厚”的精神,努力整理自己的思绪,将《Learning Perl》的
内容浓缩、提取,写写学习笔记,便于自己以后复习
1.每个Perl语言的开头,都是以类似
#! /usr/bin/perl
2.Perl的注释是从一个井号(#)一直到行尾的内容。
正常的Perl语句以分号(;)结尾;
另外,Perl的书写格式比较自由,允许随意使用无关紧要的空白。
第二章 标量数据
这章介绍了Perl语言中标量数据的概念、应用于标量数据的操作符及if和while两种控制结构。
1.标量(Scalar)数据的概念
在Perl中,单个的数字和单个的字符串都被视为标量数据。
1.1 数字标量
Perl中的数字没有整型、浮点型的区别,在Perl的内部统一用浮点型表示,对于用户来说,感觉不到差别。
八进制直接量以0开头,十六进制以0x开头,二进制以0b开头。
1.2 字符串标量
字符串是字符的序列,字符串中可以包含任意字符的组合。
在Perl中表示字符串有两种方式:单引号字符串和双引号字符串。
字符串是放在单引号'(或双引号")之间的字符序列;
1.2.1 单引号与双引号在字符串标量中的区别
在单引号间,除了单引号和反斜杠以外的任何字符在字符串中表示该字符本身;
在双引号间,则可以使用反斜杠转义字符及变量替换。
所以,若想获得纯粹的字符串,可以使用单引号;若想使用反斜杠转义字符或变量替换,则使用双引号。
1.3 数字与字符串的转换
数字转换为字符串:直接在数字上加上单引号或双引号即可,譬如把数字37变成字符串,37-->"37"。
字符串转换为数字:直接去掉单引号或双引号,并去掉非数字字符,如第一个字符不是数字,则转换后,该数字为0。
譬如"37jerry"转换为数字后,变成37;"jerry"转换为数字后,变成0。
1.4 标量变量
标量变量以$开头。
在Perl中,变量在第一次赋值前有特别的undef值,这个值对于数字来说,相当于0;对于字符串来说,相当于空串。
所以在Perl中,相当于对定义的变量已经进行了初始化,不必担心由于未初始化而出现的一些错误。
2.操作符
2.1 数值操作符
包括常规的+,-,*,/,%(求模),**(求幂)等操作符。
2.2 字符串操作符
字符串可以用.操作符连接起来。
串重复操作符x(小写字母x):这个操作符取它左边的操作数(一个字符串),生成连续的拷贝,重复次数由它右边的
操作数(一个数字)决定。譬如,"fred"x2="fredfred";
2.3 二元赋值运算符
和C语言类似,Perl中有二元赋值运算符,譬如+=,*=等。
2.4 比较操作符
比较数字:<, <=, ==, >=,>, !=。
比较字符串:lt,le,eq,ge,gt,ne(含义和上面的数字比较符对应)。
3.控制结构
3.1 if控制结构
if () {};
if () {}; else {};
3.1.1 if控制结构中条件判断的真假问题(布尔值)
几条规则:
特殊值undef是假;
0是假,其它的数字全为真;
空串('')是假,其它的字符串一般是真;
一个例外:因为数字和字符串是等价的,所以0的字符串形式,'0',和它的数值形式有同样的值:假。
这点是和C语言有区别的地方。
总结:标量值为undef,0,'',或'0'时,为假;所有其它的标量都为真。
3.2 while控制结构
while(){};
4.有用的函数
4.1 取得用户输入
使用行输入操作符:$line = ;
$line是自己定义的标量变量,Perl以换行符判断一个行输入的结束,同时换行符也会存储在变量$line中。
4.2 chomp操作符
chomp作用于字符串,用于去掉字符串结尾的换行符且只能去掉一个,如果该字符串末尾不是换行符,则chomp什么也不做。
chomp($line);
chomp $line; #也可以
这涉及到Perl的一个基本规则:除非去掉括号会改变意思,否则括号总是可有可无的!!!
4.3 defined函数
用于判断一个变量是undef还是非空字符串,可以使用defined函数,它对undef返回假,其它所有情况返回真。
第三章 列表和数组
本章讲述了列表和数组的概念、针对列表和数组的一些运算符和函数,并着重阐明了Perl中重要的“上下文”的概念。
1.列表和数组的概念
列表(list):是一个有序的标量集合;
数组(array):是一个包含列表的变量。
因此,简单地说,列表是数据,而数组是变量。
在Perl中不需要事先定义数组的大小,数组的大小总是可以根据需要自动扩展和收缩,没有被赋值或预定义的数组元素其值为undef。
1.1 访问数组及数组元素
对整个数组的访问很简单,在数组名前面加上@符号即表示整个数组,如@array。
使用索引访问数组元素,索引从0开始,逐渐递增,和C语言相同。
譬如数组名为array,则访问数组元素的方式为:$array[index]。
一个数组的最后一个元素的索引值为$#array(array为该数组名)。
Perl中还提供了一种从数组尾部访问数组元素的快捷方式:
负的数组索引从数组的尾部算起。
譬如,$array[-1]表示array数组的最后一个元素。
1.2 命名空间的概念
在Perl中,标量、数组和后面章节将要讲的散列的变量名是在不同的命名空间,
你可以在同一个程序中定义一个名为Jerry的标量,
名为Jerry的数组和名为Jerry的散列,而Perl不会讲它们搞混,因为它们本来就没在一个命名空间。
要记住的是访问类型的变量,需要使用不同的前缀,可以认为前缀是命名空间的名字。
以$开头的总是标量,
以@开头的总是数组,
以%开头的总是散列。
2.针对列表和数组的运算符和函数
2.1 ".."运算符
".."运算符表示一个区间,譬如1..5,表示从1到5的五个数字(1 2 3 4 5),一般用于列表或数组的赋值中。
2.2 qw快捷方式
qw表示“被括引的单词(quoted words)”,用于将一些字符序列赋值给列表或数组。
譬如要将fred, barney, betty,wilma和dino赋值给数组array,如果不用qw快捷方式,
则需@array = ("fred", "barney", "betty", "wilma","dino");这样需要键入大量的双引号。
如果使用qw,则为@array = qw /fred barney betty wilma dino /;
注意qw快捷方式后面使用的分隔符是任意的,可以使用//,也可以使用!!或<>等,只要这两个匹配即可。
2.3 pop和push操作符
这两个操作符将数组当作堆栈来处理,pop用于从数组中弹出一个数据,push用于向数组中压入一个数据,针对的都是数组的尾部。
语法:$var = pop @array; push @array, $var;
2.4 shift和unshift操作符
这两个操作符的功能和pop与push类似,只是它们针对的是数组的头部进行操作。
语法:$var = shift @array; unshift @array, $var;
2.5 foreach控制结构
这个控制结构用于遍历整个数组,语法为:
foreach $var (@array) {};
要注意的是在遍历数组时,$var不是数组元素的拷贝,它就是数组元素本身,因此在{}中改变$var将改变array数组本身。但是,在遍历结束后,$var将恢复遍历数组前的值,即如果遍历数组前,$=10,则遍历完成后,$var仍然等于10。
2.6 reverse操作符
reverse操作符取一个列表的值(可以是来自一个数组),然后返回相反顺序的列表。
记住reverse只是返回反序列表,它并不影响它的参数。
因此,如果返回值不被赋给别的变量,它就毫无用处。
语法:@var = reverse @array;
2.7 sort操作符
sort操作符取一个列表的值(可以是来自一个数组),然后按照内部字符序进行排序。
对ASCII字符串,就是按照ASCII字母表的顺序。sort和reverse相同,不影响它的参数,
因此,你必须把你要的结果赋给别的变量。
3. 上下文的概念
上下文指的是一个表达式是在哪里出现的。
它实际上就是一个简单的思想:
一个给定的表达式在不同的地方,可能会有不同的含义。
当Perl解析你的表达式时,它总是期望一个标量值或一个列表值或一个其它的值。
Perl的期望就被称作表达式的上下文。对Perl中具体上下文的认识需要在实践中逐步领会。
譬如:
5 + something; # something必须是个标量
sort something; # something必须是个列表
一个有意思的现象是,当把一个数组赋值给一个标量时,这个标量获得这个数组的元素的个数,$var = @array;
有些时候需要强制使用标量上下文,这时可使用一个假函数scalar通知Perl,这里需要一个标量上下文。如scarlar@array;
在列表上下文中,从<STDIN>获得的数据存储在一个数组中,每行为一个数组元素。@lines= <STDIN>; #在列表上下文中读取标准输入
3.1 Perl的缺省变量$_
在任何需要使用标量变量的地方,都可以省略不写,而Perl会自动使用缺省变量$_表示这个变量。
譬如:
foreach (1..10) { #缺省使用$_
print "I can count to $_!n";
}
第四章 子例程
本章讲述了子例程(subroutine)的概念,介绍了子例程的定义、调用格式、参数、返回值等。
1.子例程的概念
子例程和其它编程语言中函数的概念类似,唯一的区别是Perl中的子例程总是用户定义的,而函数可能包括系统自带的内置函数。
和标量、数组类似,子例程也有单独的命名空间,该命名空间以与字符("&")标识。
2.定义及调用格式
用关键字sub和子例程的名字定义一个子例程,如下所示:
sub max {
...
}
调用的时候,去掉sub,在子例程名字前面加"&",如下所示:
$max_num = &max($a, $b);
3. 参数和返回值
传递给子例程的参数,会自动保存在子例程内的一个默认变量@_中.
这是一个数组变量,
对其中的元素进行访问的方式为$_[i], i=0,1,...
譬如:
sub max {
if ($_[0] > $_[1]) {
$_[0];
} else {
$_[1];
}
}
默认情况下,在子例程中得到的最后一个计算值自动成为返回值,即不需要明确的return语句。
当然,使用return语句可以立即从子例程中返回一个值,并不再执行子例程的其余部分。
4. 私有变量及严格的编码规范
使用my关键字定义的变量为私有变量,其作用范围为最小的代码块。
用法如下:
my $a; #定义了一个私有标量
my ($a, $b); #定义了一个私有列表
为了告诉Perl执行严格的语法规则检查,可以把use strictpragma放在程序顶部(或在任何你希望强制使用这些规则的块或文件中)
use strict; #强制使用一些好的编程规则
5.其它
忘记local,我们用不到这个东西:P
在调用子例程时,总是使用与字符(&),这是安全和保险的。
第五章 散列
本章讲述了散列(hash)的概念、访问方法及针对散列的一些函数
1.散列的概念
散列类似于数组,与数组相同的是它可以含有任意数目的值并随意读取它们;
与数组不同的是,在散列中,使用的索引是字符串(这里成为键(key))而不是数值,
即使用名字来查找对应的值。键是任意字符串,在某个确定的散列中,它的值是唯一的。
键和值(value)都是任意的标量,但键总是被转成字符串。
2.访问方法
和标量、数组一样,散列拥有独立的命名空间。
访问散列中的元素,可以使用如下的语法:
$hash{$some_key}
访问整个散列,使用百分号(%)做前缀
%hash
3.赋值
为了方便起见,可以将散列转换为一个列表,并转换回来。给散列赋值是一个列表上下文,这个表由键-值对组成:
%some_hash={"foo",35,"bar",12.4,2.5,"hello","wilma",1.72e30,"betty","byen");
在这种赋值中,不太容易分辨键和值的对应关系,在Perl中,可以使用大箭头(=>)来表示键和值的对应关系,如下所示:
%some_hash={
"foo" => 35,
"bar" => 12.4,
2.5 => "hello",
"wilma" => 1.72e30,
"betty" => "byen",
);
散列(在列表上下文中)的值是一个简单的键-值对列表:
@any_array = %some_hash;
上式称之为展开(unwind)散列,展开时不能预知键-值对的顺序,但是键和值总是对应的。
4.散列函数
4.1 keys和values函数
my @k = keys %hash; # 获得该散列中所有的键
my @v = values %hash; #获得该散列中所有的数值
在一个标量上下文中,这些函数给出散列中的元素(键-值对)个数
my $count = keys %hash;
4.2 each函数
each函数用于遍历一个散列,每次返回一个键-值对作为一个二元素列表。
实际情况下,一般只在while循环中使用each,如下所示:
while ( ($key,$value) = each %hash) {
print "$key => $valuen";
}
上面这个例子用于遍历散列%hash,每次取一个键-值对,
并将该键-值对赋给($key,$value)列表。
当遍历完该散列时,($key,$value)=(undef,undef),
此时,while循环条件不成立,则循环结束。
为了遍历散列,也可以使用foreach和keys函数相结合的方式,采用这种方式,还可以在遍历时对散列进行排序,如下所示:
foreach $key (sort keys %hash) {
...
}
4.3 exists函数
要查看某键是否在散列中,可以使用exists函数,它在键存在时返回真,不论相应的值是真还是假:
if (exists $books{"dino"}) {
...
}
4.4 delete函数
delete函数从散列中删去指定的键(和相应的值)。(如无此键,它的任务就结束了。此时既无警告,也没有错误消息。)
my $person = "betty";
delete $books{$person}; #撤销$person的借书卡
4.5 reverse操作符
使用reverse操作符可以生成一个逆散列,即原先的键变为新散列中的值,原先的值变成新散列中的键。
如果原散列中的值不是唯一的(即值之间有重复),则无法判断新的散列中某个键对应的是哪个值。
因此,使用reverse操作符变换散列一般只适用于键和值都是唯一(不重复)的散列。
第六章 I/O基础
本章主要讲述了如何从标准输入/文件中获得输入及如何向标准输出进行输出。
1.从标准输入进行输入
使用行输入操作符<STDIN>从标准输入中获得输入。
$line = <STDIN>; # 读入一行
在循环中使用:
while (<STDIN>) {
...
}
或
foreach (<STDIN>) {
...
}
使用这种写法,行输入的数据被存储在默认的标量变量$_中,
当然也可以显式的将行输入数据赋给一个已定义的标量变量中,如$line。
上述两个循环的区别是:
while循环每次处理一行数据,而foreach循环会首先读入全部输入,然后在逐行处理。
所以,如果输入的文件很大,最好使用while循环。
2.从钻石操作符(<>)进行输入
钻石操作符被设计用来处理命令行参数(或者称为“调用参数”),可以看作是特殊的行输入操作符。
例如:
./my_program fred barney betty
my_program是命令,后面的fred、barney和betty是这个命令的命令行参数,
可能是三个文件的名字(若从标准输入进行输入,则用-表示)。
钻石操作符的作用是从命令行参数中连续获得输入数据,好像将这三个文件合并成一个大的文件后,逐行输入似的。如下所示:
while (<>) {
chomp;
print "It was $_ that I saw!n";
}
这个循环的会依次从fred、barney和betty这三个文件中读取输入,然后逐个打印出来。
3.调用参数
命令的调用参数实际存储在Perl预设的数组@ARGV中,钻石操作符从@ARGV数组中获得命令行参数信息。
譬如上面的例子中(./my_program fred barney betty),
@ARGV数组中的元素为:$ARGV[0] = fred, $ARGV[1] = barney, $ARGV[2] =betty。
程序自己的名字被存储在Perl的特殊变量$0中。
可以在程序开始后和使用钻石操作符前调整@ARGV,从而改变处理的参数(可能不是命令行参数了)。
例如,下面我们可以处理三个指定的文件,不论用户在命令行中输入了什么参数:
@ARGV = qw /larry moe curly/; # 强制读取这三个文件
while (<>) {
...
}
4.向标准输出进行输出
使用print函数向标注输出进行无格式的输出,如:print "Hello, I'm here!n";
使用printf函数向标准输出进行格式化的输出,格式化操作和C语言类似,如:printf "Hello, %s. Yourpassword expires in %d days! n", $user, $days_to_die;
格式字符串含有几个所谓的转换,每个转换以一个百分号(%)开始,以一个字母结束;在后面列表中的条目数目应该与转换的个数相同,如果它们不匹配,就很难正确工作。
%g:g表示General,要按一般较合适的方式打印一个数字,可以使用%g,它会根据需要自动选择浮点、整数,甚至是指数表示;
%d:表示十进制整数,会根据需要对数据进行截取(注意,不是舍入);类似的,%x表示十六进制,%o表示八进制;在d前面加上整数,可以表示需要打印的字段宽度,若整数为负数,则表示左对齐;
%s:表示一个字符串,它按字符串进行给定值的替换,但有一个给定的字段宽,譬如,printf "sn", "wilma";
%f:表示浮点数,它会根据需要进行舍入,可以指定小数点后的位数,譬如,printf ".3fn", 6*7 + 2/3;
%%:打印一个真正的百分号,它的特殊之处在于它不需要列表中的元素与之对应。
第七章 正则表达式的概念
笔者注:用过几次正则表达式后,为它的强大与灵活所折服,打算再深入研究一下,
本书推荐了Jeffrey E.F.Friedl编著的《Mastering RegularExpression》,已经从图书馆借的,有空研读一下:P
本章主要介绍了正则表达式的概念,还介绍了正则表达式的一些基本要素,如元字符、数量符、模式分组、选择等。
1.正则表达式的概念
书中这段讲的很好,简明易懂,我就照抄了,呵呵
正则表达式(regularexpression),在Perl中经常被成为模式(pattern),是与一个给定字符串匹配或不匹配的模板。
也就是说,有无限数量可能的文本字符串。一个给定的模式把这个无限集合分成两个组:匹配的组和不匹配的组。
不能有“可能”、“也许”、“似乎”之类的匹配:必须是要么匹配,要么不匹配。
正则表达式强调的是一种精确的概念。
2.使用简单的模式
要比较一个模式(正则表达式)和$_的内容,只需把模式放在一对斜杠(/)之间,如下所示:
$_ = "yabba dabba doo";
if (/abba/) {
...
}
表达式/abba/在$_中寻找这个四字符的字符串,如果找到了,返回真;否则,返回假。
这是一种默认模式,在下一章中将介绍如何在一个指定的变量中匹配特定的模式。
所有可以放在双引号字符串中的常见反斜杠转义符都可以被用在模式中。
3.元字符
正则表达式中有一组具有特殊意义的特殊字符,叫做元字符(metacharater)。
句号(.):匹配除了换行符(n)以外的任何单个字符;
反斜杠():在任何元字符前加一个反斜杠都会使得它不再特别;.表示一个句号,\表示一个反斜杠;
4.数量符(quantifier)
星号(*):匹配前面的条目零次或多次;
加号(+):匹配前面的条目一次或多次;
问号(?):匹配前面的条目零次或一次,即前面的条目是可选的;
这三个数量符都必须跟在某些东西的后面,因为它们就是表示前面的条目可能重复多少次。
5.模式中的分组
在正则表达式中,使用小括号("()")进行分组。譬如,模式/(fred)+/匹配类似于fredfredfred的字符串。
6.选择
竖线表示要么是左侧匹配,要么是右侧匹配,此时读做“或”,也就是说,如果模式中竖线左侧的部分不能匹配,
那么右侧的部分就有机会进行匹配。
7.一个模式测试程序
该章给了一个有趣的模式测试程序,可以用来测试自己写的正则表达式是否可以如自己所愿、匹配需要匹配的东西。
#!/usr/bin/perl
while (<>) { #一次得到一个输入行
chomp;
if (/YOUR_PATTERN_GOES_HERE/) {
print "Matched:$`<$&>$'n"; #<>之间、$后面的是与字符(&)
} else {
print "No match.n";
}
}
第八章 正则表达式提高
本章介绍了字符类、通用数量符、锚位符、记忆的小括号、反向引用及优先级等重要内容,前面的内容好懂、易
记,后面的“记忆的小括号、反向引用和优先级”的内容需要重点理解与掌握,有一定难度。
1.字符类
字符类(characterclass),即在一对中括号([])中列出的所有字符,可以匹配类中的任何单个字符,它只匹配一个字符,但该字符必须在表中。譬如[abcdwxyz]或[a-dw-z](可用短横-指定一个字符范围,上面两个字符类是等价的)。
可以用双引号字符串中类似的字符快捷方式来定义一个字符类,譬如[000-177]匹配任何7比特ASCII字符。
在字符类前加一个脱--字符(^)可以反置它,即只匹配不包含在中括号中的任何单个字符。譬如[^abc]匹配除了a、b和c之外的任何字符。注意,脱字符必须出现在中括号内字符的最前面,否则不具备反置的含义。如[a^bc]表示匹配a、^、b和c中的任一字符。
字符类的快捷方式:
d:匹配所有数字的字符类,等价于[0-9];d是digital的缩写
w:匹配所谓的“单词”字符,即普通字母、数字和下划线,等价于[A-Za-z0-9_];w是word的缩写
s:匹配空白,包括换页符、制表符、换行符、回车符和空个字符,等价于[ftnr ];s是space的缩写
D:匹配所有非数字字符类,即d的反置形式,等价于[^d];
W:匹配所有的非“单词”字符,即w的反置形式,等价于[^w];
S:匹配所有的非空白字符,即s的反置形式,等价于[^s];
2.通用数量符
使用大括号({})中的一对由逗号隔开的数字来指定重复的最少和最多次数。
/a{N,M}/:匹配重复N到M次的字符a;
/a{N,}/:匹配重复次数大于等于N的字符a,没有上限;
/a{N}/:匹配重复次数等于N的字符a,精确匹配;
3.锚位符(anchor)
^:标志字符串的头,可以理解为标志行首,譬如/^fred/匹配以fred开头的行;
$:标志字符串的尾,可以理解为标志行尾,譬如/fred$/匹配以fred结束的行;
b:单词边界锚位符,标志单词的开始与结束,用于精确匹配单词(单词中只含有w类型的字符),譬如/bfredb/精确匹配单词fred;
B:非单词边界锚位符,可以看作b的反置形式;
4.记忆的小括号及反向引用
小括号的一个功能是把模式的一些部分组合起来,它的第二个作用是要求正则表达式引擎记住与小括号中的模式匹配的那部分子串。也就是说,它不是记住模式本身,而要记住相应的部分字符串。在用小括号进行分组时,它们自动具有记忆功能。
反向引用(backreference)就是回头引用当前模式处理过程中保存的记忆。反向引用由一个反斜杠来构成,譬如,1包含第一个正则表达式记忆(即被第一对小括号匹配的字符串部分)。
反向引用被用来匹配与模式在前面匹配的字符串完全一样的字符串,譬如/(.)1/匹配任何字符,后跟同一个字符,即匹配任何双字符(如aa,11,两个连续空格等)。
反向引用使用n来标记第n个正则表达式记忆,确定n的方法是:从左到右,只数左括号的个数即可。譬如,在模式/((fredwilma)(stone))/中,1表示最外层的小括号匹配的字符串部分,2表示(fredwilma)小括号匹配的字符串,3表示(stone)小括号匹配的字符串。
在使用八进制转义字符时,如果小于100,则最高位写0,如012,以避免被误当作反向引用。
5.优先级
在介绍优先级之前,需要了解所谓的原子(atom),它是构成模式最基本的片段,可以看作不可分割的一个最小单元。原子包括独立的字符、字符类和反向引用。
正则表达式的优先级分四个级别,优先级数字越低,级别越高:
1.小括号,用作分组和记忆。小括号中的任何东西比其它东西都更紧密地“粘在一起”;
2.数量符,包括星号(*)、加号(+)、问号(?)和大括号构成的数量符;
3.锚位符和字符串序列,即一个单词中的字母粘在一起的紧密程度与锚位符粘着字母的紧密程度一样;
4.最低的优先级是表示选择的竖线。
第九章 使用正则表达式
本章介绍如何在Perl中使用正则表达式,介绍了“查找”(m//)、“替换”(s///)及split操作符、join函数的用法。
1.使用m//进行匹配
前面两章介绍的模式,都是在一对斜杠中的,如/fred/。但这实际上是m//(模式匹配)操作符的一个快捷方式,只所以说是快捷方式是因为可以选择任何定界符对把内容括住,而当选择了斜杠作为定界符时,就可以省略开始的m。譬如,m#fred#和/fred/是等价的。
有几个选项修饰符字母,也可称为标志符(flag),可以把它们附加在正则表达式的结束定界符后面,以改变表达式的缺省行为。
/i:进行不区分大小写的匹配,如/fred/i;
/s:使点号(.)可以进行任何字符的匹配,点号原先不能匹配换行符,加上这个标志符后,就可以匹配任何字符,如/fred.*lee/s;
可以组合使用标志符,组合的顺序不重要,譬如/fred/is和/fred/si是等价的。
2.绑定操作符=~
与$_匹配只是个缺省操作。绑定操作符(bindingoperator)=~告诉Perl用右侧的模式匹配左侧的字符串,而不是匹配$_。譬如:
if ($some_other =~ /brub/) {
...
}
3.在模式中替换
这里的替换指的是双引号替换,即在正则表达式中,可以把变量替换为它实际的值。进行变量替换时,需要将变量放在小括号中。譬如:
my $what = "larry";
if (/^($what)/) {
...
}
4.匹配变量和记忆的持久性
在正则表达式中使用n对匹配的字符串进行反向引用,而在Perl中,使用$n来引用匹配的字符串。两者的区别是,n回指当前正在进行匹配的正则表达式的第n个记忆,$n表示一个已经完成的模式匹配的第n个记忆。两者有个时间差,即在同一时刻指的并不是同一个字符串。譬如:
$_ = "Hello there, neighbor";
if (/s(w+),/) { # 记住空格和逗号之间的单词
print "the word was $1n"; # $1 = Hello there
}
匹配变量一般保留到下一次模式匹配成功,即一个不成功的匹配会维持以前记忆的原状,但一个成功的匹配则全部重新设置它们。这是模式匹配一般总是在if或while的条件表达式中的一个原因。由于记忆不会永远保持,所以一般在模式匹配的后面马上使用这个记忆的变量,或者将这个记忆的变量拷贝到一个普通变量中,以便后面继续使用。譬如:
if ($wilma =~ /(w+)/) {
my $wilma_word = $1;
...
}
在Perl中,有三个系统定义的模式匹配变量,即你无须自己定义这些变量即可使用它们:
$`:保存正则表达式引擎在找到匹配之前需要跳过的部分;
$&:保存实际与模式匹配的那部分字符串;
$':保存模式没有到达的字符串的剩余部分;
将这三个字符串按顺序连在一起,你总会得到原字符串:$`$&$'。
5.用s///进行替换
使用s///可以用一个替换字符串来替换一个变量匹配模式的部分,譬如:
$_ = "He's out bowling with Barney tonight.";
s/Barney/Fred/; # 用Fred替换Barney
s///有一个返回值,如果替换成功,则返回真;否则,返回假。
和m//类似,s///可以使用绑定操作符=~ 改变匹配的变量,譬如:
$file_name =~ s/Barney/Fred/;#在$file_name中查找Barney并将其替换为Fred
和m//类似,s///也可以使用不同的定界符,此处不再赘述。
和m//类似,s///使用一组标志符来改变缺省行为:
/g:进行全局替换,如果没有这个标志,则s///仅替换匹配的第一个模式;
/i,/s:用法和m//中的类似,此处不再赘述;
6.大小写转换
在替换的时候,可能经常希望替换字符采用了合适的大写(或小写,依需要而定)。这很容易用Perl来完成,即通过一些反斜杠转义。
U转义符强制后面的字符都用大写,譬如:
$_ = "I saw Barney with Fred";
s/(fredbarney)/U$1/gi; #$_现在是"I saw BARNEY with FRED."
L转义符强制后面的字符都用小写;
缺省情况下,U和L会影响其后的所有(替换)字符串,除非使用E关闭大小写转换,譬如:
$_ = "I saw Barney with Fred";
s/(w+) with (w+)/U$2E with $1/i; # $_现在是"I saw FRED withBarney."
当写成小写的形式时(l和u),它们只影响下一个字符,譬如:
$_ = "I saw barney with fred";
s/(fredbarney)/u$1/gi; # $_现在是"I saw Barney with fred."
uL(或Lu)表示全部小写,但是第一个字符大写;
7.split操作符
split操作符把一个字符串按照分割子(separator)分开。格式如下:
@result = split /separator/, $string;
split操作符在字符串中用模式/separator/扫一遍,返回一个由分割子分割的字段(子字符串)的列表。每当模式匹配时,就是一个字段的结束和下一个字段的开始,因此,任何可以匹配模式的东西都不会出现在返回的字段中。譬如:
@result = split /:/, "abc:def:g:h"; # @result = ("abc", "def","g","h")
8.join函数
join函数完成split操作符相反的功能:split把一个字符串分成若干片段,而join则把一组片段粘合起来形成一个字符串。格式如下:
my $result = join $glue, @pieces;
join的第一个参数是粘合串,它可以是任何字符串。另一个参数是由片段组成的一个列表,join把粘合字符串放在片段之间。譬如:
my $x = join ":", 4,6,8,10,12; # $x = "4:6:8:10:12"
第十章 不常用的条件控制语句
第十一章 文件句柄和文件测试
本章介绍如何读写文件及测试文件的类型,是日常编程中重要的内容。
1.文件句柄的概念
文件句柄(filehandle)是Perl程序中的一个名字,表示你的Perl进程与外面世界的I/O连接。
也就是说,它是一个连接的名字,并不一定是一个文件的名字。
文件句柄
文件<====================>进程
2.文件句柄的命名
命令文件句柄的方式和其它Perl标识符一样(字母、数字和下划线,但不能以数字开始),
但文件句柄名没有前缀字符。为了避免和Perl的保留字(关键字)冲突,一般文件句柄名全部用大写字母。
3.打开一个文件句柄【or是否则的意思】
open MYFILE " > myfile" or die "Cannot Createmyfile:$!";
其中,MYFILE是文件句柄名,myfile是实际的文件名,>表示向该文件中写入数据(<表示从该文件中读取数据,>>表示向该文件中追加数据);
若打开文件出错,会执行die语句,终止程序执行,并给出错误信息,$!用于给出错误信息。
4.关闭一个文件句柄
close MYFILE;
5.使用文件句柄
一旦打开了一个文件句柄,就可以读入行,像使用STDIN从标准输入读取一样,譬如:
open MYFILE " > myfile" or die "Cannot Createmyfile:$!";
while (<MYFILE>) {
...
}
一个为写入或追加而打开的文件句柄可以和print或printf一起使用,紧跟在其后但在参数列表之前:
print LOG "Captain's log, stardate 3.14159n"; # 输出到LOG
print STDERR "%d percent complete.n", $done/$total*100;
6.文件测试
Perl有一组完整的测试,可以用它们了解文件的信息,譬如某个文件是否存在,是否可读、可写等。
所有的文件测试都有一个短横和一个字母,它们是测试的名字,后面是一个要测试的文件名或文件句柄,
一般会返回一个真/假值。用法如下:
if (-e $filename) {
...
}
常用的文件测试及它们的含义:
-r : 文件或目录对该用户或组可读
-w : 文件或目录对该用户或组可写
-x : 文件或目录对该用户或组可执行
-o :文件或目录被该用户所有
-e :文件或目录存在
-z :文件存在,大小为零(对目录总为假)
-s :文件或目录存在,大小非零(单位为字节)
-f :条目是个普通文件
-d :条目是个目录