perl cheetsheets

比整个屏幕长的脚本都应该加上use strict;

数据元素

变量

当你需要声明一个复杂的字符串时,可以使用heredoc语法:

1
2
3
4
5
6
7
my $blurb =<<'END_BLURB';
He looked up. "Change is the constant on which they all
can agree. We instead, born out of time, remain perfect
and perfectly self-aware. We only suffer change as we
pursue it. It is against our nature. We rebel against
that change. Shall we consider them greater for it?"
END_BLURB

Undef

Perl里的undef表示一个未分配、不确定、未知的值。
一个声明了但是没有定义的标量值就是undef:

1
2
my $name = undef; # unnecessary assignment
my $rank; # also contains undef

数字

Perl支持整型数字和浮点数字,你可以使用不同的方式来表示它们,二进制、八进制、十进制、十六进制:

1
2
3
4
5
6
my $integer = 42; #整型
my $float = 0.007; #浮点型
my $sci_float = 1.02e14; #科学计数法,浮点数
my $binary = 0b101010; #二进制0b前缀
my $octal = 052; #八进制0前缀
my $hex = 0x20; #十六进制0x前缀

还可以使用下划线来增加可读性:(注意不是逗号,因为逗号在Perl中有特殊意义)

1
2
3
my $billion = 1000000000;
my $billion = 1_000_000_000;
my $billion = 10_0_00_00_0_0_0;

列表

列表list 标量的有序集合;数组array 储存列表的变量

使用范围操作符(..)可以很方便的创建列表:

1
2
my @chars = 'a' .. 'z';
my @count = 13 .. 27;

可以使用qw()操作符分隔空白来产生字符串列表:

1
my @stooges = qw( Larry Curly Moe Shemp Joey Kenny );

数组操作

压入、弹出

1
2
my $fred = pop(@array) # pop从右边弹出;shift从左边弹出
push (@array,$a) # push从右边压入;unshift从左边压入

最后一个元素的索引 $trees[$#trees]

reverse 反向 @fred = reverse @fred #本身不修改

排序

1
2
3
4
my @result = sort by_number @some_numbers
my @result = sort { $a <=> $b} @some_numbers; # <=> 符号表示数字的比较和排序
my @string = sort {$a cmp $b} @any_strings; # cmp 表示字符串的比较和排序
my @string = sort {"\L$a" cmp "\L$b"} @any_strings; # \L表示忽略大小写

1
2
3
4
5
6
7
sub by_score_and_name {
{$score{$b} <=> $score{$a}} # 按照value对key做降序排列
or
$a cmp $b # 按照字母顺序再排序
}

流程控制

条件分支、循环

使用后缀形式,添加括号增加可读性:

1
2
3
print "yes\n" if ($a>1);
print "$_" for 1..10

三目操作符

三目操作符(? :)可以根据给定的条件选择执行表达式.

条件表达式为真时执行表达式1,条件表达式为假时执行表达式2:
条件表达式 ? 表达式1 : 表达式2

1
2
3
4
5
my $time_suffix = after_noon($time)
? 'afternoon'
: 'morning';
push @{ rand() > 0.5 ? \@red_team : \@blue_team }, Player->new;

循环控制

next-立即进入下一循环:

last-立即结束循环。

redo-重新进入当前迭代,返回本次循环的顶端(无需评估循环条件)。

循环嵌套时,可能不容易让人理清楚结构,这时可以使用标签:

1
2
3
4
5
6
7
8
9
10
LINE:
while (<$fh>){
chomp;
PREFIX:
for my $prefix (@prefixes){
next LINE unless $prefix;
say "$prefix: $_";
# next PREFIX is implicit here
}
}

哈希

访问哈希

访问键

1
2
3
for my $addressee (keys %addresses){
say "Found an address for $addressee!";
}

访问值

1
2
3
for my $address (values %addresses){
say "Someone lives at $address";
}

访问键值对
each 函数,唯一使用地方就是在while循环中

1
2
3
while (my ($addressee, $address) = each %addresses){
say "$addressee lives at $address";
}

用哈希去重复用法

1
2
3
4
5
6
my %uniq;
undef @uniq{ @items };
my @uniques = keys %uniq;
# @items是需要去重的数据,@uniques是去重后的
# 对哈希切片使用undef就是将所有的切片值设置为undef。

exists 函数:检查哈四中是否有某个键

1
2
3
if (exists $books{"dino"}) {
print "Hey, there's a library card for dino!\n";
}

反转 松绑哈希

1
2
%inverse_hash = reverse %any_hash # 反转哈希 键值互换
@any_array = %some_hash; #哈希松绑,把哈希转化成 键/值 对的列表

去除哈希里的键

1
delete $h{$a}

符号

数学操作符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
+ 加
- 减
* 乘
/ 除
** 乘方
% 模,取余 10%3 余数为1
+=,-=, *=, /=, **=, %= 组合形式
-- 前缀自减
== 相等
!= 不等
> 大于
< 小于
>= 大于等于
<= 小于等于
<=> 排序中的比较符号

自增 自减

1
2
3
4
5
6
7
8
自增++ 自减--
操作符++放在变量之前就能先增加变量的值,然后获取标量的值。
$m = 5;
my $n = ++$m; # $m 增加到 6,并把该值赋给 $n
$m = 5;
my $d = $m++; # $d 得到的值为 $m 之前的值 5 ,然后 $m 增加到6

双引号里的转义字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
\n #换行
\r #光标回到最左边
\t #水平制表符
\f #换页符
\b #退格
\a #系统响铃
\e #Esc(ASCII编码的转义字符)
\007 #任何八进制的ASCII值(此例中007表示系统响铃)
\x7f #任何十六进制的ASCII值(此例中7f表示删除键的控制代码)
\cC #控制符,也就是control键的代码(此例中表示同时按下Ctrl和C键的返回码)
\\ #反斜线
\" #双引号
\l #将下个字符转为小写
\L #将到\E为止的所有字符转为小写
\u #将下个字符转为大写
\U #将到\E未知的所有字符转为大写
\Q #将到\E为止的非单词(non-word)字符串加上反斜线
\E #结束\L,\U或\Q

字符串操作符

字符串操作符为操作数提供字符串语境。比如

1
2
3
4
5
6
7
8
9
正则表达式的绑定操作符(=~, !~)
字符串连接符(.)
字符串比较操作符(eq)
不等 ne
小于 lt
大于 gt
小于或等于 le
大于或等于 ge
还有sort排序中的字符串比较操作符(cmp)

逻辑操作符

逻辑操作符为操作数提供布尔语境。如&&, ||, and, or,//,三目操作符(?:) 逻辑非 (!), not (优先级比!低) ,还有xor。
注意//和||的区别,操作符//只要目标操作数有定义就为真,即使是0和空字符串。

优先级:
括号 > 量词 > 锚位和序列 > 择一(竖线|) > 字符、字符集、反向引用

位操作符

位操作符提供的是数字语境。这些操作符不太常见。
左移位(<<),右移位(>>), 逐位与运算(&), 逐位或运算(|), 逐位异或运算(^), 以及组合形式(<<=,>>=,&=,|=,^=)。

特殊操作符

自增操作符(++)的行为比较特别,当操作数是数字时就数值加一。如果是字符串就增长字符串。

重复操作符(x)也有着复杂的行为,在列表上下文中将列表重复;在标量上下文中,重复并连接成一个字符串。

范围操作符(..),在列表语境下会生成从一个操作数到另一个操作数的列表,可以是数字也可以是字符串。
在布尔语境下行为很不一样:操作符初始值为假,在左操作数为真时整体变为真值,持续这个状态直到右操作数为真时,整体再转变变为假值。

1
2
3
4
5
6
7
8
9
10
11
12
#列表语境
my @cards = ( 2 .. 10, 'J', 'Q', 'K', 'A' );
#布尔语境
foreach my $x ( 1..10 ){print $x if $x == 3..$x == 4}
# 打印 3 4
#利用该特性来方便地提取邮件正文:
while (/Hello, $user/ .. /Sincerely,/)
{
say "> $_";
}

正则表达式

竖线 | 或 意思是左边或右边匹配都行

正则表达式 可进行双引号内插

可选修饰符: 可连起来使用,顺序不影响结果

1
2
3
4
5
6
7
/i # 不分大小写
/s # 用点号(.)匹配任意字符
/x # 加入空白
/g # 全局匹配修饰 第一次匹配后 立即进行下一次匹配/替换
/m # 跨行模式匹配

锚位

1
2
3
4
^ # 表示字符串的开头
$ # 表示字符串的结尾
\b # 单词锚位 /\bfred\b/ 整词搜索

命名捕获
为捕获串加标签 (?<name>PATTERN) print "$name"

通用变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{} 重复次数的范围
/a{5,15}/ 字母a重复5到15次的匹配
/(fred){3,}/ fred重复3次以上
/(fred){8}/ 重复8次
* {0,}
+ {1,}
? {0,1}
# 非贪婪量词
# 在贪婪量词后面加?
* *?
+ +?
? ??

函数

函数参数

1
2
3
4
5
6
7
8
9
sub show_pets_by_type{
my ($type, %pets) = @_; #记得要先将标量分出来
while (my ($name, $species) = each %pets){
next unless $species eq $type;
say "$name is a $species";
}
}
# 列表赋值是贪婪的,所以上面例子中%pets会吞掉 @_ 里面所有剩下的值。所以如果$type参数的位置是在后面,那么就会报错,因为所有的值先被哈希吞掉,但是却发现单了一个。

验证参数

某些时候参数验证是很容易的,比如验证参数的个数:

1
2
3
4
5
sub add_numbers{
croak 'Expected two numbers, received: ' . @_
unless @_ == 2;
...
}

有时则比较麻烦,比如要验证参数的类型。因为Perl中,类型可以发生转换。如果你有这方面的需求,可以看看这些模块:Params::Validate和MooseX::Method::Signatures。

输入和输出

调用参数 @ARGV由调用参数组成的列表,开始运行时,@ARGV已经塞满了调用参数。

6个特殊的文件句柄是perl保留的:

STDIN STDOUT STDERR DATA ARGV ARGVOUT

使用say来输出 与print相比会再每行输出的结尾z自动加上换行符

printf格式化输出

1
2
printf "Hello, %s; your password expires in %d days!\n", $user, $days_to_die;
# %s 代表字符串 $user; %d 代表数字 $days_to_die
1
2
3
4
%d 十进制整数,自动舍去小数点后数字
%s 字符串格式,可设定字段宽度 printf "%10s\n","wilma"; (正数右对齐,负数左对齐)
%f 转换格式(浮点数,四舍五入),可指定小数点后输出位数 printf "12.3f\n",42 + 2/3; (宽度12,小数点3位)
%% 要输出百分号,使用 %%
1
2
3
4
5
6
# 直接给字符串
# Format number with up to 8 leading zeroes
my $result = sprintf("%08d", $number);
# Round number to 3 digits after decimal point
my $rounded = sprintf("%.3f", $number);

perl套路

perl打乱list顺序

perl -MList::Util=shuffle -e 'print shuffle(<STDIN>);' < myfile

perl随机打乱数组

1
2
use List::Util;
@array = List::Util::shuffle @array;