:[.,\d]+))/ {
say "The location of Gene $1 is $3!";
}
这一点,在反向引用数目过多,数不清括号来的时候便颇为好用了:)
新增的短路操作符:定义否// (实用性:4星)
恩,我们知道,善用短路操作符&&(即 and)、||(即or)会使得程序简洁而直观,比较常见的是打开文件句柄的例子:
open INPUT, "<", "$ARGV[0]" || die "Cannot open file: $!";
即当||的左边为真(打开文件成功)时,右边短路不会报错。5.10版的Perl新添了定义否的短路操作符//。它有什么功效呢?看看这个例子:
my $signal = $gene_signal{$gene} || "NaN";
say "$gene\t$signal"; #当$gene_signal{$gene}等于0时,会输出NaN
这个代码里,我们想在哈希表里检索微阵列的gene对应的信号,如果检索的gene在哈希表里不存在,就是这块芯片不含该基因的探针,我们将信号值定为缺失值NaN,便于下一步用R处理。但这里有个问题,就是当gene对应的信号值为0的时候,||左边的表达式为假,$signal将会定义为缺失值,这显然不是我们的本意,解决办法是采用定义否操作符//:当只有//左边的表达式为undef时,才使用右边的值。
my $signal = $gene_signal{$gene} || "NaN";
say "$gene\t$signal"; #当$gene_signal{$gene}等于0时,会输出0
非常智能的智能匹配(实用性:5星)
我想善解人意是Perl的一个非常重要的哲学思想,智能匹配是很好的体现;一旦学会,你会很快在新写的程序用到它。
简单的说,智能匹配操作符(~~)能根据两端的数据类型进行比较,一个一目了然的例子是:
say "The two gene groups are the same!" if @gene1 ~~ @gene2;
没错,它能快速比较两个数组是否相同(当然,数组元素的顺序也要考虑);它的功能远不止如此,基本标量,数组,哈希,甚至匹配模式,任意两两组合,它就能进行你想要的(一般情况下)的智能匹配,另外一个神奇的例子是
say "Yes, miR-310 is a newly evolved miRNA!" if %new_miR_target ~~ /miR(-?)310/i;
猜到了吧,这段代码会在%new_miR_target的key中检索/miR(-?)310/i这个pattern,如果有符合的对象便say yes。事实上,一张较完整的~~功能表如下(摘录自Learning Perl, 5ed, p224)
事实上熟悉了它看起来复杂的规则,你一定会爱上它。
类switch控制结构:given-when(实用性:4星半)
我想每一个C程序员都会抱怨Perl为什么没有switch这样的控制结构,而不得不选择繁杂的多层
if...elsif..elsif.....else。事实上,give-when就是一个新版升级的switch。基于智能匹配的表达
式,given-when显然更加强大。
given($flybase_id) {
when(/^fbgn/i) {say "It's a gene!"}
when(/^fbtr/i) {say "It's a transcript!"}
when(/^fbpp/i) {say "It's a polypeptide!"}
default {say "I've no idea what it is."}
}
有细心的人会注意到:我们没有添加和switch语句配套的break,当表达式为真时不会跳出而会一直往下落(俗称fall-through)。
事实上,和switch颇为不同的是,switch是默认fall-through,而Perl中的given-when默认是当表达式为真时执行语句,
然后跳出控制块!对,所以以上的程序并没有错,如果要实现fall-through,需要添加continue控制符。
given($flybase_id) {
when(!/^fbgn/i) {say "It's not a gene!"; continue}
when(!/^fbtr/i) {say "It's not a transcript!"; continue}
when(!/^fbpp/i) {say "It's not a polypeptides!"; continue}
default {say "I've no idea what it is."} #多么不自然的一个例子啊
}
奇妙的是,如果判断对象不是标量,而是数组,或者是哈希展开的键值(总而言之,是列表即可),直接用foreach替代given可以达到遍历整个列表的效果:
foreach (@flybase_id) {
when(/^fbgn/i) {say "It's a gene!"}
when(/^fbtr/i) {say "It's a transcript!"}
when(/^fbpp/i) {say "It's a polypeptide!"}
say "Moving to default...";
default {say "I've no idea what it is."}
}
是的,我们还可以在when语句之间添加其他的语句,不错吧^ - ^
一个Summary
智能匹配应该是最值得称赞的功能呢,相信很多程序会因为这个功能缩减了几行,Perl的设计哲学也渗透于其中。
say函数看起来比较不起眼,但是也算是贯彻了Perl的另外一个哲学思想:”能少按键就少按键吧!“;天知道print某天会不会变成pt。
Perl一个令人”诟病“之处在于其内置了相当多的奇怪变量,这次5.10版本在捕捉命名功能上更是采用了%+,使得程序更加像火星语了。其实
Perl程序员会觉得这样写起来更得心应手,更酷呢^-^。很多人提及Python的好处,我也不只一次动心过:简洁易懂的语法,严谨的格式,面向对象的
特性,但每次尝试moving to
Python的时候,都会觉得某些Perl的习惯已经深植于意识了。常见的莫过于丢弃一切可以丢弃的括号,能用系统变量就用系统变量吧——这些都是
Python相当鄙弃的恶习。其实呢,脚本语言(Perl/Python/Ruby
etc)只要精通一门就可以胜任一切日常工作了;对于写软件亦或者复杂计算这样的工作,编译性语言,如C/C++/java等,是更好的选择。所以,掌握
两件语言当居家必备、行走江湖的利器,任何bioinformatics的工作都不在话下啦。
所以下辈子也许我会选Python当脚本语言,这辈子我就随了Perl吧 :)