perl语法重点-知识手册

hashes
%表明是一个hash表,如%hash
{}用于hashes的访问,如%hash{"fred"}="finished";
%some_hash = (“foo”, 35, “bar”, 12.4, 2.5, “hello”, “wilma”, 1.72e30, “betty”, “bye\n”);
以key,values方式将后面的值保存到%some_hash,如%some_hash{"bar"}值为12.4.
@array_array = %some_hash;
将一个hash的值存入列表,注意保存后的顺序可能和原hash的顺序不同。
my@k = keys %hash;
kes函数返回%hash的key
my@v = values %hash;
values函数返回%hash的values
while (($key, $value) = each %hash){print “$key => $value\n”;}
each函数可迭代hash 的每一个元素,将返回下一个 key/value 对
也可使用foreach迭代,如
foreach $key (sort keys %hash){
$value =$hass{$key};
print “$key => $value\n”;
#也可以不使用额外的临时变量$value
#print “$key => $hash{key}\n”;}
exists 函数,如果hash 中存在此 key,则返回true,如
if(exists $books{$dino}){print “Hey, there’s a libaray card for dino!\n”;}
delete函数将某个给定的 key(包括其对应的value)从hash 中删除,如果不存在这个key,则什么也不做,如:
delete $books{$person}; #将$person 的借书卡删除掉

正则表达式
. 它可以匹配任何单个的字符,但不包括换行符(“ \n”)。如果要匹配句号.,则应使用\.$
* 表示匹配前一项0次或者多次
? 其含义是前面一个项出现一次,或者不出现。
+ 意思是可以匹配前面一项的一个或多个
() 用来表示分组 例如,模式/fred+/能匹配上如fredddddddd,/(fred)+/能匹配上像fredfredfred这样的字符串
| 在这种用法中通常被读作“ 或(or)” ,意思是匹配左边的或者右边的。/fred( |\t)+barney/这样的模式,它将匹配 fred,barney以及中间由空格,制表符(tab),
或者二者混合所组成的字符串
\d 任何数字的类,[0-9]
\w [A-Za-z0-9_]
\s [\f\t\n\r ],其含 5 个空白字符:格式符(form-feed);制表符(tab),换行符,回车,以及空格符
\D, \W, \S 匹配它们对应的小写形式不能匹配上的字符
[\d\D] 它的意思是任何数字,和任何非数字,则意指任何字符。这是匹配所有字符的一种通用方法,甚至包括换行符,而点(.)匹配除换行符以外的任何字符
m// 匹配,实际上可以使用任何成对的分隔符而不限于//,如{}()[],但如果使用//可省略m
/i 不区分大小写,如/yes/i,匹配yes的各种大小写
/s 匹配任何字符,包括换行符,与[\d\D]类似
/x 添加空格,由于/x允许模式中使用空白,那么模式中的空格,制表符将被忽略,另,Perl中,注释可以被作为空白,因此使用/x,可以在模式中加上注释,如
/
\d+ #小数点前一个或多个十进制数字
\.? #可选的小数点
/x #模式结束
^ 表示在字符串的开头进行匹配

,$ 则表示在结尾,如/^\s*$/,它将匹配一个空行
\b 词界锚定,如/\bfred\b/可以匹配上单词fred,但不能匹配frederick,alfred, man fred mann
\B 非词界锚定,如模式/\bsearch\B/将匹配searches, searching, searched, 但不能匹配search,或者 researching。
=~ 绑定操作符,对$_进行匹配只是默认的行为,如需对某一变量匹配,则应为,$some_other =~ /\brub/,表示对$some_other进行匹配,一个特殊的例子
my $likes_perl = ( =~ /\byes\b/i);将用户输入与yes进行匹配,返回一个boolean值给$likes_perl.
$1 匹配变量,此类变量还有$2,$3等等,其个数与模式中的()个数一致。此类变量的值为含有括号中的模式所匹配的字符串。如
$_ = “Hello there, neighbor”;
if(/(\S+) (\S+), (\S+)/){
print “words were $1 $2 $3”;
其输出为 words were Hello there neighbor。
注意:这些匹配变量的值会保持不变,直到下一个模式成功匹配为止。
$&,$`,$' $`中含有正则表达式引擎在匹配成功前所找到的变量,而$'为此模式还没有匹配的剩余部分。如果将这三个变量放在一起,你将得到原始字符串
{} 一般的数量词,如/(fred){3,}/匹配3个或者更多个fred,其实:星号(*)等同于{0,},表示 0 个或多个。加号(+)等同于{1,},表示 1 个或多个。而问号(?)则等同于{0,1}。
s /// 查询并替换
$_ =“He’s out bowling with Barney tonight.”;
s/Barney/Fred/; #Barney被Fred 替换掉
print “$_\n”; #现在 $_ 为“He’s out bowling with Fred tonight.”
s/with (\w+)/agaist $1’s team/;
print “$_\n”; #为 “He’s out bowling against Fred’s team tonight”;
/g 进行全局替换,默认s///只进行一次替换而无论是否还有其它地方匹配。如
$_ =“Input data\t may have extra whitespace.”;
s/\s+/ /g; #现在是 “Input data may have extra whitespace.”
s/^\s+|\s+$//g; #将开头,结尾的空白去掉
\U 要求紧接着的均是大写
$_ =“I saw Barney with Fred.”;
s/(fred|barney)/\U$1/gi; #$_现在是 “I saw BARNEY with FRED.”
\L 也可以要求后面的均为小写
$_ =“I saw Barney with Fred.”;
s/(fred)|barney/\L$1/gi; #$_现在是 “I saw barney with fred.”
\E 改变\U\L的影响范围
$_ =“I saw Barney with Fred.”;
s/(\w+) with (\w+)/\U$2\E with $1/I; #$1现在是 “I saw FRED with barney.”
\l和\u 同\L\U,但只作用于下一个字符
?: 将?:加入()的开头以表示括号为非捕获用,形式如,(?:),例
/(?:bronto)?saurus (steak|burger)/ #此时第一个括号匹配后不会存入$1中,第二个括号则不变

条件结构语句
if for foreach while unless untill与其它编程语言无多大区别
perl中可将语句写在前后跟条件,如,print "i'm jings!" if($name -eq "jings");
last 退出循环,与break同
next 结束当前循环次数,重新进

入下一次循环,与continue同
redo 这个标记在其它语言中没有,作用为结束当前循环,重新开始循环,但不计算循环条件,相当于重新开始本次循环,个人觉得用来验证输入挺不错,可以省略一个循环语句。

文件操作
open 打开文件句柄,如下有几种格式
open CONFIG, “dino”;
open CONFIG, “open BEDROCK, “>fred”;
open LOG,“>>logfile”;
值得注意的是,第三种情况下,如果文件名中包含>字符,如>fred,则语句变成了open BEDROCK,">>fred",这与我们初衷不同,因为此时打的文件已经变成了向fred文件追加了,此时,如果perl
在5.6版本后,可使用
open BEDROCK,">","$FILENAME";
close 关闭文件句柄 如,close BEDROCK;
die 打印出你给它的消息(利用标准错误流),并确保程序退出时为非零(nonzero)的退出状态(exit status),可结合使用$1,如,
open LOG, ">>logfile" or die "Cannot create logfile:$!";
以上表示,如果打开文件失败,则结束程序,并输出提示信息,注意$1是系统产生的一些可读的信息,如果使用die来表明错误,但此错误不是系统请求失败引起的,则不要使用$!
另外注意,die默认将Perl程序的名字和行数输出在消息的末尾,如果不想要函数和文件的名字,只需在 die 消息后面加上换行符,如
die "Not enough arguments\n" if(@ARGV<2);
warn 警告信息,与die同,但不退出程序
-e 存在文件,如
die “Oops! A file called‘$filename’already exists.\n”
if –e $filename;
-M 文件修改日距离当前时间的天数,如
warn “Config file is looking pretty old!\n”
if –M CONFIG > 28;

表 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 为管道(Entry is 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 索引节点修改时间(单位:天)

stat 给出文件或文件句柄所有的信息,如
my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blockes)=stat($filename);
stat命令与linux的stat命令同.
localtime 返回时间,如
my $timestamp = 1180630098;
my $date = localtime $timestamp;
my($sec, $min, $hour, $day, $mon, $year, $wday, $yday, $isdst)=localtime $timestamp;
$mon 是一个表示月份的数字,范围是 0 到11,其在月份名字的数组中作为索引值是比较方便的。$year 是指从 1900 到现在的年份数,因此,需要加上 1900来得到实际的年数。
$wday 的值是从0(星期天)到6(星期六),$yday 指一年中的具体天数(从0(1 月1 日)到364 或365(12月31))。
gmtime 同 localtime一样,除了其返回的形式为是世界时间(曾经被叫做格林威治时间)
time 得到当前的时间,可使用time函数

目录操作
chdir可以改变工作目录,如
chdir “/etc”or die “cannot chdir to /etc: $!”;
globbing shell将每个命令行中的任何的文件名模式转换成它所匹配的文件名,此类操作称作glob,如
my @all_files = glob “*”;
注意,<>中也可为globbing,文件句柄也使用<>,Perl根据尖括号之间是一个严格意义上的标识符,则其为文件句柄读入操作;否则,为globbing操作,如果
my @files = ; ##glob
my @lines = ; ##文件句柄读入
my $name = “FRED”;
my @files = <$name/*> ##glob
opendir 打开目录句柄,它不是读入文件的内容,而是将一个目录中的文件名(以及一些其它东西)读入,readdir 操作返回的文件名没有路径名部分,而只是文件名,如果需要路径名,如下:
opendir SOMEDIR , $dirname or die “Cannot open $dirname: $!”;
while (my $name = readdir SOMEDIR) {
next if $name =~ /^\./; #跳过点文件
$name = “$dirname/$name”; #加上目录名
next unless–f $name and –r name; #除非是可读文件
}
unlink 删除文件,返回值为成功删除的文件数,
unlink “slate”, “bedrock”, “lava”;
由于unlink 以一个列表作为操作,而glob返回列表,因此可以将它们结合起来,一次删掉多个文件:
unlink glob “*.o”;
通过返回值可以判断文件是否成功删除,如
unlink $file or warn “failed on $file: $!\n”;
rename 将一个给定文件重命名,如
rename “old”, “new”;
link 创建连接,应该是硬连接,如
link“chicken”, “egg”
symlink 创建符号连接,如
symlink “dodgson”, “carroll”or warn “Can’t sysmlink Dodgson to carroll: $!”;
mkdir 建新目录,注意格式,如
mkdir “fred”, 0755 or warn “Cannot make fred d

irectory: $!”;
0755是权限,此处0755造成不能用括号,否则perl会认为是十进制的755.此外,如果使用变量,则需使用oct($perm),因为直接使用变更时perl仍会将之作为字符串解释,使用oct函数则将其
解释为八进制。
rmdir 删除空的目录,如
rmdir glob “fred/*”; #删除fred/下面所有的空目录
chmod 改变文件或目录的权限,如
chmod 0755, “fred”, “barney”;
不能使用u+x等符号权限。
chown 改变一批文件的所有者及所在的组,函数返回其改变的文件的个数,而错误值被设置在$!之中。如
my $user = 1004;
my $group = 100;
chown $user, $group, glob “*.o”;
另外,如果知道用户名而不知道其ID,可使用getpwnam函数,它将名字转换为数字,而对应的 getgrnam将组名转换为数字。如
defined(my $user = getpwnam “merlyn”) or die “bad user”;
defined(my $group = getprnam “users”) or die “bad group”;
chown $user, $group, glob “/home/Merlyn/*”;

字符串和排序
index函数 返回第一个字符的位置。字符位置是从 0 开始编号的,如果子串不存在,则返回-1 如
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 = “Yabba dabba doo!”;
my $where1 = rindex($fred, “abba”); #$where1 得到 7
my $where2 = rindex($fred, “abba”, $where - 1); #$where2 得到1
substr 只处理部分的字符串,如
my $mineral = substr(“Fred J. Flintstone”, 8, 5); #得到“Flint”
my $pebble = substr “Fred J. Flintsone”, 13; #得到 “stone”
my $out = substr (“some very long string”, -3, 2); # $out 得到 “in”
省略第三个参数时,默认截取到串尾,第二个参数为负数时,表示从串尾开始,最后一个字符为-1,倒数第二个字符为-2,类推.
一个特别的用法如下:
my $string = “Hello, world!”;
substr($string, 0, 5) = “Goodbye”; # $string 现在变成了 “Goodbye, world!”
以上语句将$string中的前5个字符替换成了Goodbye,这种用法相当于其它高级语言中的replace,另外,还可以使用=~来将替换限制特定部分,事
substr($string, -20) =~ s/fred/barney/g;#将$string中后20个字符中的fred替换成barney.
还可以使用以下方式进行替换
my $previous_value = substr($string, 0, 5, “Goodbye”);
sprintf函数 返回格式化字符串,同printf,但不printf打印.一个不错的例子如
$number=12345678.9;
$number = sprintf “%.2f”, shift @_;
#在do-nothing 循环中,每一次加入一个逗号
1 while $number =~ s/^(-?\d+) (\d\d\d)/$1,$2/;
#将美元符号放入合适的位置

$number =~ s/^(-?)/$1\$/;
注意while循环的写法,只要替换部分返回 true(表明成功),则循环就会持续下去.
<=>,cmp 太空船符号,很搞怪的名字,我也不知道怎么取名了,这两个操作符是用来进行数字和字符串排序的,用法如下:
sub by_number {$a <=> $b }
它们用在比较子程序中,注意这个子程序,并没有给变量$a,$b赋值,因为这两个变量perl自动会处理,上述子程序表示比较传给它的两个参数,如果$a<$b,返回1,$a>$b返回-1,相等返回0,
如下为这个排序子程序的使用方法
$number=sort by_number @some_number;
上面的子程序还可以直接和sort写在一行,如
$number=sort {$a<=>$b} @some_number;
将@some_number按升序排序,如果要降序,可以将使用{$b<=>$a},即将$a,$b交换一下位置.
cmp的使用与<=>一样,只不过它是用来比较字符串的,如
sub ASCIIbetically {$a cmp $b} my@string = sort ASCIIbetically@any_strings;
也可以使用cmp来创建更复杂的排序,如大小写无关的排序:
sub case_insenstive {“\L$a”cmp “\L$b”}
不要在排序子程序中修改变量$a,$b的值,因为它们不是数据的副本,而是原始数据.
对hashes排序,如
my %score = (“barney”=>, “fred”=>205, “dino”=> 30);
sub by_socre { $score{$b} <=> $score{$a}}
my @winners = sort by_score keys %score;

进程管理
system 调用子进程来运行程序 如
system“date”;
system ‘ls–l $HOME’;
system “ls–l \$HOME”;
注意语句2用的是单引号,语句3用的是双引号.
另外,如果system不只一个参数,此时不会调用shell,如下
my $tarfile = “something*wicked.tar”;
my @dirs =qw(fred/flintstone betty );
system“tar”, “cvf”, $tarfile, @dirs;
#@dirs中的目录名,shell 也不会处理它,如果当成一个参数
system“tar cvf $tarfile @dirs”; #Oops!
此时shell会处理,它会将一些内容倾入flintstone命令,并将其作为后台运行,再打开betty作为输出,显然得到完全不同的两种结果,因此,一般应使用多个参数来调用.
exec 基本上与system相同,区别之处在于system调用后会返回到调用处继续执行,而exec则会在调用时结束perl进程,调用结束则perl进程也结束了.
%ENV 保存环境变更的hash,如
$ENV{‘PATH’} = “/home/rootbeer/bin:$ENV(‘PATH’)”;
delete $ENV{‘IFS’};
my $make_result = system “make”
`` 反引号捕捉输出,system,exec只是将结果输出到标准输出,而引号则可捕捉输出,如将其保存到变量.
my $output_with_errors = `frobnitz –enable 2>&1`;
将标准输出的标准错误保存到变量中,大多数时候,都需要这样做,否则perl会将标准错误输出到终端上,造成误解.
my $result = `some_questionable_command arg arg argh 将标准输入重定向,如

果我们不清楚是否需要输入,有时也需要这样做,因为引号并不能接受用户输入.
open 使用文件句柄同步进程,此时仍然是Perl 在控制,调入命令,(通常)等待其结束,可能捕获其输出。但Perl也可以在调用子进程时仍保持运行,与之交互
open DATE, “date|”or die “cannot pipe from date: $!”;
open MAIL, “|mail merlyn”or die “cannot pipe to mail: $!”;
my $now = ;
print MAIL“The time is now $now”; #假定$now由换行符结尾
进程是同步的,同管道命令一样。如果尝试读时,数据还没准备好,则进程被悬挂(不会消耗额外的 CPU时间)直到数据准备好为止。同样的,如果一个写进程在读进程之前,
写进程将慢下来,直到读进程跟上来,如
open F, “find / -atime +90 –size +1000 –print|”or die “fork: $!”;
while() {
chomp;
printf %s size %dK last accessed on %s\n”,
$_, (1023 + -s $_)/1024, -A $_;
}
发送和接收信号
kill 2, 4201 or die “Cannot signal 4201 with SIGINT: $!”;
将信号2(SIGINT)发送给进程号为4201的进程.
特殊的信号码0 的含义是:“检查是否可以发送信号,如
while (kill 0, $pid) {warn “$pid has gone away!”;}
捕捉信号,如
sub clean_up{
unlink glob “$temp_directory/*”;
rmdir $temp_directory;
}
$SIG{“int”} = 'clean_up';
变量%SIG的赋值将激活 clean_up,直到撤销为止。key 为没有前缀 SIG 的信号名,值为没有&的子程序名.
eval 捕获错误,并将错误信息保存在$@中,如
eval { $barney = $fred / $dino };
print “An error occurred: $@”if $@;
上面语句中如果$dino为0,则会引起错误,此时程序不会崩溃,因为eval会捕获它,并将错误信息保存在$@中.
grep 从列表得到元素,grep 第一个参数是一个块,其中$_依次为列表中的每一个值,返回一个Boolean(true/false)值。剩下的参数是相应的列表。grep 会首先计算表达式的值,
这和 foreach循环一致。如果块中最后一个表达式的返回值为true,则这个元素会被返回,如
my @odd_numbers = grep {$_ % 2} 1..1000;得到1-1000的所有奇数.如果表达式简单,也可用如下形式
my @odd_numbers = grep $_ % 2,1..1000;
表达式也可为下则表达式,下列从文件句柄中查找符合正则表达式的值.
my @matching_lines = grep {/\bfred\b/i} ;
map 对列表项进行变换,与上面grep使用方法一致.如
print “Some powers of two are:\n”,map “\t”. (2 ** $_) . “\n”, 0 ..15;
slices 使用它可以只返回列表中的部分元素,如我们想得到@names中的第一个元素和最后一个元素,可如下:
my($first, $last) = (sort @names)[0, -1];
注意,此处括号不能少,否则会引起语法错误,但如果没有sort,则可以不用括号.另外,注意区分列表引用,$names[1],它用的是$,

且[]中有一个数字,而此处用的是@names[0,-1],用的是@表示整个
列表,[]中可有多个数字.
slice的下标可以是任意的序列,甚至可以是重复的。下例将具有十个元素的列表中的五个元素取出:
my @names = qw{ zero one two three four five six seven eight nine };
my @numbers = ( @names)[ 9, 0, 2, 1, 0 ];
print “Bedrock @numbers \n”; #输出 Bedrock nine zero two one zero
也可对hash使用slice,如
my @three_scores = @score{ qw/ barney fred dino/ };
my @three_score = ($score{“barney”}, $score{“fred”}, $score{“dino”});
上述两种方法等价,显然第一种方法更简单效率.


相关文档
最新文档