第七章:正则表达式
Q1:Perl如何使用正则表达式?常用的正则表达式有哪些?
答:[1]要匹配某个模式(正则表达式)和$_的关系,可以将模式放在正斜线(//)之间,如下:
$_ = “yabbadabba doo”;
if(/abba/){
print “Itmatched!\n”;
}
表达式/abba/将在$_寻找这四个字母。如果找到,则返回true,在本例中,它出现了不止一次,但结果没什么不同。总之,
如果找到了,则匹配上;如果没找到,则没匹配上。
由于模式匹配通常返回 true 或 false,因此经常用在if 或while 的条件表达式部分。
[2]
[2.1]简单的模式
[2.1.1]点(.)通配符
点(.)是通配符,它可以匹配任何单个的字符,但不包括换行符(“\n”)。因此,模式/bet.y/将匹配betty。同时也匹配betsy, 点(.)只匹配一个字符。
[2.1.2]星号(*)
星号(*)表示匹配前一项0次或者多次。因此,/fred\t*barney/将匹配上fred 和barney
之间有任意个制表位(tab)的字符串。
[2.1.2]加(+)
加(+)的意思是可
以匹配前面一项的一个或多个:/fred +barney/意思是fred 和barney 之间由空格分开,且只能是空格。至少是一个
[2.1.3]问号(?)
问号(?),其含义是前面一个项出现一次,或者不出现。也就是说,前面这个项出现 1 次或者 0次,此外不会有其它情况。因此,/barm-?bamm/只匹配:bamm-bamm 或bammbamm。这很容易记住:“前面的这个项,出现?或者不出现?”
[2.1.4]括号(())用来表示分组
模式/(fred)+/能匹配上像fredfredfred 这样的字符串
[2.1.5]竖线(|)
竖线(|),在这种用法中通常被读作“或( or)”,意思是匹配左边的或者右边的。如果竖线左边没有匹配上,则匹配右边。因此,/fred|barney|betty/将匹配出现过fred,或者barney,或者betty 的字符串。
[2.2]字符类
[2.2.1]方括号[]
可以匹配上括号内出现的任意单个字符。它匹配一个字符,但这个字符可以是列中的
任意一个。
例如,字符类[abcwxyz]可以匹配上括号内七个字母中的任意一个。
[2.2.2]连字号(-)
为了方便,我们可以使用连字号(-)来表示某个范围的字母,因此上例也可以写做[a-cw-z]。
[2.2.3]符号^
字符类前使用符号^将取此字符类的补集。也就是说,[^def]]将匹配上这三个字符中之外的任意单个字符。[^n\-z]将匹配上n, -, z 之外的任何字符。
[2.2.4]字符类的简写
任何数字的类,[0-9],可以被简写为:\d
\w 被称作“word’字符:[A-Za-z0-9_]。
\s 对于匹配空白(whitespace)将非常方便
它等价于[\f\t\n\r],其含 5 个空白字符:格式符(form-feed);制表符(tab),换行符,回车,以及空格符。
[2.2.5]简写形式的补集
三种简写形式的补集[^\d],[^\w], 和[^\s]
等价于\D, \W, \S
第十章:更多控制结构
Q1:perl中除了IF控制结构还有哪些控制结构?各控制结构的语法定义是怎样的?
答:
[1.1]unless控制结构
unless的含义是:除非条件为真,否则执行块中的代码。这和在if 语句的条件表达式前面加上!(取反)所得结果是一样的。
unless($mon =~ /^Feb/){
print “This month has at least thirty days.\n”;
}else{
print “Do you see what’s going on here?\n”;
}
等价于:
if($mon=~ /^Feb/){
print “Do you see what’s going on here?\n”;
}else{
print “This month has at least thirty days.\n”;
}
[1.2]until控制结构
有时,希望将while 循环的条件部分取反。此时,可以使用until:
until($j >$i){
$j *=2;
}
这个循环一直执行,直到条件表达式的返回值为真为止。它和while 循环非常类似,只是在条件为假时重复执行,而不是在条件为真的情况下执行。
[1.3]裸块控制结构
被称为“裸的”块是指没有关键字或条件的块。
假如有一个while 循环,大致如下:
while(condition){
body;
body;
body;
}
将关键字while 和条件表达式去掉,则有了一个“裸的”块:
{
body;
body;
body;
}
“裸的”块看起来像while 或foreach 循环,除了它不循环外;它执行“循环体”一次,然后结束。它根本就没循环!
[1.4]elsif语句
if(!defined$dino){
print “The value is undef.\n”;
}elsif($dino =~ /^-?\d+\.?$/){
print “The value is an integer.\n”;
}elsif($dino =~ /^-?\d*\.\d+$/){
print “The value is a _simple_ floating-point number.\n”;
}elsif($dino eq ‘’){
print “The value is the empty string.\n”;
}else{
print “The value si the string ‘ $dino’.\n”;
}
[1.5] for控制结构
for($i= 10; $i >=1; $i--){
print “I can count down to $i\n”;
}
[1.6]循环控制
[1.6.1] last操作
last 会立刻结束循环。(这同 C 语言或其它语言中的“break”语句类似)。它从循环块中“紧急退出”。当执行到last,循环即
结束,如下例:
#输出所有出现fred 的行,直到遇见_ _END_ _标记
while(<STDIN>){
if(/_ _ END_ _/){
#这个标记之后不会有其它输入了
last;
}elsif(/fred/){
print;
}
}
##last 跳转到这里##
[1.6.2]next操作
有时还不希望结束循环,但本次循环已经结束。这种情况下,next 是非常适用的。它跳到当前循环块的最后面(块内)◆。
next 之后,又会进入下一轮循环(这和 C 或者类似语言的“continue”相似):
◆我们这里又撒了一个小谎。事实上, next 跳到循环的conttinue(通常省略)块的开头处。参见perlsyn 了解详细的信息。
#分析输入文件的单词
while(<>){
foreach(split){ #将$_分拆成单词,并依次赋给$_
$total++;
next if/\W/; #不是“words”的被跳过
$valid++;
$count{$_}++; #对每个单词进行计数
##next 跳到这里##
}
}
print “totalthings = $total, valid words = $valid\n”;
foreach $word (sort keys %count){
print “$wordwas seen $count{$word} time.\n”;
}
这几乎是到目前为止所出现过的最复杂例子,让我们一步一步地分析它。
last, next 可以在这 5 种循环中使用:for, foreach, while, until, 或者“裸”块。如果块是嵌套的,next 在最里层工作。
[1.6.3] redo操作
循环控制的第三个操作是redo。它会调到当前循环块的顶端,不进行条件表达式判断以及接着本次循环。(在 C 或类似语
言中没有这种操作。)下面是一个例子:
#输入测试
my @words = qw{ fred barney pebbles dino Wilma betty } ;
my $errors = 0;
foreach(@words){
##redo 跳到这里##
print “Typethe word ‘$_’ :”;
chomp(my $try = <STDIN>);
if($try ne $_){
print “sorry–That’snot right.\n\n”;
$errors++;
redo; #跳转到循环顶端
}
}
print “You’vecompleted the test, with $errors errors.\n”;
和其它两种操作一样,redo 可以在 5种循环体内工作,当在嵌套循环体中时,它在最内层使用。
第十一章:文件检验
Q1: perl可针对哪些文件状态信息进行检测?分别使用的函数是什么?
答:
[1]表 11-1 文件检测选项及其含义
检测选项含义
-r 文件或目录对此(有效的)用户(effective user)或组是可读的
-w 文件或目录对此(有效的)用户或组是可写的
-x 文件或目录对此(有效的)用户或组是可执行的
-o 文件或目录由本(有效的)用户所有
-R 文件或目录对此用户 (real user)或组是可读的
-W 文件或目录对此用户或组是可写的
-X 文件或目录对此用户或组是可执行的
-O 文件或目录由本用户所有
-e 文件或目录名存在
-z 文件存在,大小为 0(目录恒为false)
-s 文件或目录存在,大小大于0(值为文件的大小,单位:字节)
-f 为普通文本
-d 为目录
-l 为符号链接
-S 为socket
-p 为管道(Entryis a named pipe(a “fifo”))
-b 为block-special 文件(如挂载磁盘)
-c 为character-special 文件(如 I/O 设备)
-u setuid 的文件或目录
-g setgid 的文件或目录
-k File or directory has the sticky bit set
-t 文件句柄为TTY(系统函数isatty()的返回结果;不能对文件名使用这个测试 )
-T 文件有些像“文本”文件
-B 文件有些像“二进制”文件
-M 修改的时间(单位:天)
-A 访问的时间(单位:天)
-C 索引节点修改时间(单位:天)
-r, -w, -x 以及-o 检测相应的属性对 effective user 或 group ID 是否为真,它是指实际负责运行此程序的用户◆。这些检测通
过查看文件的权限位(permission bits)。如果你的系统使用访问控制列表(Access Control Lists(ACLs)),则这些测试就使用它。
这些选项检测其权限,但并非说这种操作一定能进行的。例如,-w
示例:
die“Oops! A file called ‘ $filename’ already exists.\n”
if –e $filename;
[2] stat 和 lstat函数
虽然这些检测项可以很好的给出文件或文件句柄相应参数的属性,但它们还没有包括所有的信息。例如,它们不能给出文
件的连接数,或者所有者的user ID(uid) 。要得到文件的其余信息,可以使用stat 函数,其返回Unix 系统调用stat 时相同的
值(比你想知道的还多)
my($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime,$blksize, $blockes)
= stat($filename);
$dev和$ino
文件的设备号和索引节点号。它们组成了文件的“牌照(licenseplate)”。即便它有多个名字(硬连接(hard link)),设
备号和索引节点号的组合仍是唯一的。
$mode
文件的权限位以及一些其它的位。如果使用过Unix 命令ls –l 来得到文件的详细信息,其每一行由类似于–rwxr-xr-x 开
头。这些字母以及连接线( 9 个)◆是指文件的权限,它们对应于$mode中最不重要的位,在本例为0755。其它位,
除了这最低的9 位外,是指文件的其余信息。 mode 需要将它和本章后面的位操作结合起来使用。
$nlink
文件或目录的(硬)连接数。是指被检测项真实名字的个数。对于目录其值总是2 或者更大的数,而对于文件(通常)
是1。我们将在第十二章中讨论建立文件的连接,到你你将更清楚。对于ls –l,其为紧接权限位串的数字。
$uid 和$gid
指文件所有权的user ID 及group ID。
$size
返回其大小,单位:字节,同–s 文件检测项相同。
$atime, $mtime, 及$ctime
这三个时间,它们按照系统的时间格式: 32 位,表示从某个时刻到现在所经过的秒数,这个时刻是记录系统时间的一
个任意值。在Unix 和别的某些系统中,这个时刻从世界时间 1970 年第一个午夜开始,但在某些系统中,这个时刻可
能不同。本章后面有更多的关于如何将时间转换为有用格式的信息。
当stat 的参数是符号连接时,其返回的信息是此符号连接指向的实体的信息,而非符号连接本身的信息,除非此符号连接
所指向的内容不能被访问。如果需要得到(几乎是没用的)符号连接本身的信息,可以使用lstat 代替stat(它按照相同的
顺序返回同样的值)。如果其操作数不是符号连接,则lstat 和stat 返回的值相同。
同文件检测(filetests)一样,stat 和lstat 的默认参数为$_,意指stat 系统调用将针对$_所对应的文件进行操作。
[3]localtime函数
my($sec,$min, $hour, $day, $mon, $year, $wday, $yday, $isdst)
= localtime $timestamp;
第十二章:目录操作
Q1:perl提供的文件目录操作有哪些?请分别列出程序实例。
答:
[1]改变当前工作目录
chdir可以改变工作目录。它和Unix shell 下的cd 命令类似:
chdir“/etc” or die “cannot chdir to /etc: $!”;
[2]获取目录
my$dir_to_process = “/etc”;
opendirDH, $dir_to_process or die “Cannot open $dir_to_process: $!”;
foreach $file(readdir DH) {
print “one file in $dir_to_process is $file\n”;
}
closedir DH;
[3]递归目录
File::Find
[4]删除文件
由于unlink 以一个列表作为操作,而glob 返回列表,因此可以将它们结合起来,一次删掉多个文件:
unlink glob “*.o”;
或者
foreachmy $file (qw(slate bedrock lava)) {
unlink $file or warn “failed on $file: $!\n”;
}
[5]重命名文件
将一个给定文件重命名可以很简单的使用rename 函数做到:
rename “old”, “new”;
[6]创建和删除目录
在一个目录下创建新目录是很容易的。使用mkdir 函数:
mkdir“fred”, 0755 or warn “Cannot make fred directory: $!”;
要删除一个空的目录,按照类似于unlink 函数的方法使用rmdir 函数:
rmdir glob “fred/*”;#删除fred/下面所有的空目录
foreach my $dir (qw(fred barney betty)){
rmdir $dir or warn “cannot rmdir $dir: $! \n”;
}
和unlink 一样,rmdir 返回删除的目录个数,如果一次删除一个,则会在失败时设置合理的$!值。
[7]修改权限
chmod0755, “fred”, “barney”;
[8]修改所有者
如果操作系统允许,你可以使用chown 函数改变一批文件的所有者及所在的组。所有者及组是同时改变的,它们两个分别有一个数字值 user-ID 及 group-ID。例如:
my$user = 1004;
my $group = 100;
chown $user, $group, glob “*.o”;
[8]改变时间戳
一个时间戳方便使用的值是“现在(right now)”,time 函数返回的值,其格式是合适的。更新当前目录下的所有文件,使它们看起来是昨天修改的,而访问时间为现在,可以如下做到:
my $now = time;
my $ago = $now -24*60*60; #一天的秒数
utime $now, $ago, glob “*”; #设成当前访问的,一天之前修改的
第十三章:字符串和排序
Q1:perl如何定位一个字符串中某个子中?
答:[1]index函数总是报告子串出现的第一个位置。可以使用可选的第三个参数要求它从后面的某个地方开始查询,它会告诉index从什么位置开始:
my$stuff = “Howdy world! ”;
my $where = index($stuff, “wor”);
my$stuff = “Howdy world!”;
my $where1 = index($stuff, “w”); #$where1 得到 2
my $where2 = index($stuff, “w”, $where+1); #$where 得到6
my $where3 = index($stuff, “w”, $where+1); #$where 为-1(没有找到)
[2]有时,你可能想知道某个子串最后出现的位置
rindex函数也有可选的第三个参数;此时,它给出的是可能的最大值:
my $fred = “Yabbadabba doo!”;
my $where1 = rindex($fred, “abba”); #$where1 得到7
my $where2 = rindex($fred, “abba”, $where - 1); #$where2 得到1
my $where3 =rindex($fred, “abba”, $where2-1); #$whrere3 得到-1
Q2:perl如何截取子串?
答:my $mineral = substr(“Fred J.Flintstone”, 8, 5); #得到“Flint”
my $out= substr (“some very long string”, -3, 2); # $out 得到“in”
Q3:perl如何对给定的字符串进行格式化,比如统一大写,统一小写等?
my$data_tag = sprintf “%4d/%02d/%02d %02d:%02d:%02d”,$yr, $mo, $da, $h, $m, $s;
my$money = sprintf “%.2f”, 2.49997;
Q4:perl如何对字符串内部进行排序?
Q5:perl的高级排序体现在什么地方?如何实现?为什么?如果不这样实现还有什么其它方法?
答:cmp 或者ó
@patrons_IDs= sort {
&fines($b)<=> &fines($a) or
$items{$b}<=> $items{$a} or
$family_name{$a}cmp $family_name{$a} or
$personal_name{$a}cmp $family_name{$b} or
$a<=> $b
}@patron_IDs;