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]},

    • );

    1. 当想传递给子程序的参数是多于一个的数组时一定要使用引用。

    2. 一定不要在子程序中使用形如 (@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

引用

当函数返回一个引用之后,其引用变量的作用域范围多大?