wiki:perllearningnotes
Wiki: Perl Learning Notes
2006/10/18 by Julian
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 返回天数,该文件最后访问时间 ... 见<<Learing Perl>> 140页表
特殊变量
$_ 标量 @_ 列表 $_{_} Hash值
@ARGV 包含参数的列表
$^I 对<>操作符,如果没有指定文件名,则其从标准输入流中自动打开和关闭一 系列文件进行读入。但如果$^I 中有字符串,这个字符串则会成为备份文件的扩展 名
$! 系统错误信息
%ENV 环境变量表,比如 $ENV{'PATH'}
$@ 当使用 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,或者$_和@_ 等等
$& 匹配中的整个字符串
$` 匹配成功前的那一部分
$' 还没有匹配的剩余部分(使用以上三个变量会降低效率,不如替换成$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 对列表进行转换,重新输出
控制结构
for与foreach在Perl中是等价的,Perl根据其后的括号来判断循环行为
善于利用or die书写良好的风格:do this or die
模块
一个模块的例子,取名为Personal.pm
#!/usr/bin/perl
package Personal;
sub adv {
my @input = @_;
my $total;
$total+=$_ for (@input);
$adv = $total/scalar(@input);
}
1;
使用该模块
#!/usr/bin/perl
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,它将属于一个类,也便成了对象。对象知道自己属于哪个类,引用则不属于任何类。
心得
Perl有十分多的在线文档,可以用perldoc获得,比如
perldoc -f func_name
用来获取函数func_name的说明
perldoc perlreftu
获取引用教程
perldoc perlfaq4
Perl的FQL里边有好多非常棒的使用经验
map
从赋值来看,List和Hash的差别只是在于list是数组方式分赋值,而Hash是数对方 式的赋值,因此常常把List转化到一个Hash可以这样:
%hash = map { $_, 1} @list
map一般理解是返回一个列表的
@an_list = map { $_ } @list
引用
当函数返回一个引用之后,其引用变量的作用域范围多大?