[TOC]
Perl’s philosophy
There is more than one way to do it. No unnecessary limits.
文件操作
open LOG,"< filename"
打开文件句柄print FILE $out;
向文件句柄写while(<LOG>)
使用文件句柄select LOG
选择文件句柄$|
用来清空文件句柄<>
diamond操作符,实现类UNIX工具方式。不需要使用open,默认逐行操作一 个文件。比如while(<>){ print; }
就是 cat 的效果。
文件检测
-e $filename
返回布尔值,判断文件是否存在-M FILEHANDLE
返回天数,该文件最后修改时间-s $filename
返回文件大小,以Byte为单位-A $filename
返回天数,该文件最后访问时间 … 见《Learning Perl》140页表
特殊符号
$_
隐式标量……$.
行号@_
列表$_{_}
Hash值
@ARGV
包含参数的列表$^I
对<>操作符,如果没有指定文件名,则其从标准输入流中自动打开和关闭一系列文件进行读入。但如果$^I
中有字符串,这个字符串则会成为备份文件的扩展名$!
系统错误信息%ENV
环境变量表,比如$ENV{'PATH'}
,$ENV{'PWD'}
$@
当使用eval{};
结构时,保存程序失败原因
符号?的用法
- 在原来的操作符后加
?
,表示尽可能少的匹配而不是尽可能多的匹配,比如+?,*?,{2,10}?
等等,它在解析html块的时候很有用 - 非捕捉用法,比如
/(?:ronto)?saurus/
,此时的ronto只是用来分组,而不会添加到变量$1中
注意事项
- 使用
@
来引用list - 使用
%
来引用hash,比如hash反转%A = reverse %A
- 读取list元素写作
$list[1]
,如果写作@list[1]
将取出一个列表,这个 列表中包含对应该索引的一个元素,同理,读取列表中的一组元素@list[1,4]
,称作 array slice,它的效果跟($list[1],$list[2])
是一样的。 - 读取hash元素写作
$hash{$key}
,hash同样有 hash slice,比如@hash{qw/key1 key2/}
,得到的同样是slice列表 - 直接用
($item1,$item2)
表示列表,常用于赋值,比如slice用法my(undef, $item1, undef, $item2) = split /:/
; 其中undef
表示不关心的内容。 - 直接利用索引来引用列表,比如
my $myitem = (stat $filename)[9]
,则上边 可以表示为my($item1,$item2) = (split /:/)[1,-1]
,其中 -1 表示列表中 最后一个元素。
regex
\d
[0-9]\w
[A-Za-z0-9_]\s
[\f\t\n\r]\D
[^\d]\W
[^\w]\S
[^\s]- 模式匹配
m//
可以省略m,或者 m{} //i
忽略大小写//s
使.匹配换行符/\bwords\b/
单词锚定,如果写作/words\b/
表示锚定单词结尾-
Perl的变量作用域,比如 模式匹配 之后的
$1
,$2
,或者$_
和@_
等等例如, 一个把C语言定义转化成PHP定义的模式匹配:
open FILE, "< filename"; while(<FILE>){ if(/define (STAT_\w+) (\d+)(.*)/){ print "define('$1', $2); $3"; } }
$&
匹配中的整个字符串$
匹配成功前的那一部分$'
还没有匹配的剩余部分(使用以上三个变量会降低效率,不如替换成$1
,$2
这些)s///
匹配后替换(一次),例如替换$line
中的$pattern
为$replace
:$line =~ s/$pattern/$replace/
/g
全局替换/m
辨认内部换行符
字符串限定符号
\U
和\L
可以强制该变量内的字符大写或者小写,比如 “\L$a
”
常用函数
split ":", $string
类似php的explode函数@field = split /limiter/, $string;
join ":", @array
和split相反,类型php中的implode函数glob "*.bak"
选取所有的以.bak结尾的文件到一个列表
字符串操作
index($string, $pattern)
类似C中的strchr或者PHP中的strstr不过这里可以 匹配字符串,而非单字符。逆方向的匹配为rindex
substr($string, $begin, $length)
类似PHP中有同样的函数。不过Perl中的比 较神奇,可以当作左值进行替换操作。比如substr($string,0,5) = $replace
,则 $replace 将会替换掉 $string 中的前5个字符,$replace长度不 限。这段的传统写法是使用第四个参数substr($string,0,5,$replace)
。当 然,这些事情用regexp也同样可以搞定。
排序
- 三向比较符
<=>
和cmp
,前者返回三种值,后者返回两种值 sort by_number @array
不过常写作内联函数sort {$a<=>$b} @array
。值得 注意的是 sort 不能对hash进行排序,它只是对hash的keys或者values进行排 序,比如sort by_number keys %hash
对列表的操作
grep {} @array
比如找出文件中匹配的行返回一个新的列表grep {/\bpattern\b/} <FILE>
,它的作用是和UNIX命令grep一致的。map {} @array
对列表进行转换,重新输出
获取当前时间
使用localtime
和time
函数,例如:
my ($sec,$min,$hour,$day,$mon,$year,$weekday,$yeardate,$savinglightday) = (localtime(time));
my $timstr = sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year+1900,$mon+1,$day,$hour,$min,$sec);
控制结构
for
与foreach
在Perl中是等价的,Perl根据其后的括号来判断循环行为- 善于利用
or die
书写良好的风格:do this or die
模块
-
一个模块的例子,取名为Personal.pm
package Personal; sub adv { my @input = @_; my $total; $total+=$_ for (@input); $adv = $total/scalar(@input); } 1;
-
使用该模块
use strict; use Personal; my @grades = (67, 73, 57, 44, 82, 79, 67, 88, 95, 70); my $adv = Personal::adv(@grades); print $adv."\n";
引用
- 获取list引用的变量
@{$list_ref}/${$list_ref}[1]
- 获取Hash引用的变量
%{$hash_ref}/${$hash_ref}{key}
-
匿名引用的作用在于可以将标量、列表和Hash都转化成标量来存贮,这样可以构 造更加有弹性的数据。比如
my @john_grades = (65, 87, 92, 77, 53); my %john = ( id => '7821434', birth => '1983/11/12', grades => \@john_grades ); ... my %students = ( john => \%john, ...);
-
通过引用,可以获得跟php中的array一样有弹性的数组,这次不需要把那些变 量表露出来。其中array使用中括号[],hash使用花括号{}。
#!/usr/bin/perl use strict; my %students = ( john => { id => 'foo', tel => '11223344', grades => [34, 56, 78]}, paul => { id => 'bar', tel => '223344', grades => [44, 55, 66]}, );
一些注意事项:
- 当想传递给子程序的参数是多于一个的数组时 一定要 使用引用。
- 一定不要 在子程序中使用形如
(@variable)=@_;
的语句处理参数,除非你想把 所有参数集中到一个长的数组中。
类
代码重用 的经典案例.
sub new {
my $class = shift; # Get the request class name
my $this = {};
bless $this, $class # Use class name to bless() reference
$this->doInitialization(); return $this;
}
可以多次bless
一个引用对象,然而,新的将被bless的类必然把对象已被bless的引用去掉,对C和Pascal程序员来说,这就象把一个指针赋给分配的一块内存,再把同一指针赋给另一块内存而不释放掉前一块内存。总之,一个Perl对象每一时刻 只能 属于一个类。 对象和引用的真正区别是什么呢?Perl对象被bless以属于某类,引用则不然,如果引用被bless,它将属于一个类,也便成了对象。对象知道自己属于哪个类,引用则不属于任何类。
奇淫技巧
flip-flop结构
打印文本中所有夹在begin行和end行之间的内容:
while (<>) { print if /^begin/../^end/ }
一般有两种用法:
/regexp1/../regexp2/
实际相当于($_ =~ /regexp1/)..($_ =~ /regexp2/)
,以满足regexp1
为入口条件,满足regexp2
为出口条件lineno1..lineno2
实际相当于($.==lineno1)..($.==lineno2)
,这个表示特定行,print if 5..12
表示打印文件的第5行到第12行
心得
Perl有十分多的在线文档,可以用perldoc
获得,比如
perldoc -f func_name
用来获取函数func_name的说明perldoc perlreftu
获取引用教程perldoc perlfaq4
Perl的FAQ里边有好多非常棒的使用经验
map
从赋值来看,List和Hash的差别只是在于list是数组方式分赋值,而Hash是数对方式的赋值,因此常常把List转化到一个Hash可以这样:
%hash = map { $_, 1} @list
而在map看来,它所能理解的只是一个列表,所返回也是一个列表:
@an_list = map { $_ } @list
引用
当函数返回一个引用之后,其引用变量的作用域范围多大?
原先记录在Google Pages上。