Chinaunix首页 | 论坛 | 博客
  • 博客访问: 600005
  • 博文数量: 69
  • 博客积分: 2204
  • 博客等级: 大尉
  • 技术积分: 808
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-11 22:37
个人简介

..微笑着看着杯中的花茶一片片撑开.. ..透明的花瓣里水破开的声音很轻微..

文章分类

全部博文(69)

文章存档

2018年(1)

2017年(2)

2016年(10)

2015年(8)

2014年(6)

2013年(6)

2012年(4)

2011年(8)

2010年(12)

2009年(12)

分类: Python/Ruby

2012-02-07 22:14:23

原文地址:http://bio-doc.blogbus.com/logs/69202499.html
抽两天空把第五版的小骆驼读了一遍,觉得5.10版的Perl还是有很多能实用的新特性的!方便自己使用,总结了一下,有兴趣的同学可以去读读小骆驼书。此番,让我对Perl 6更加期待。

以下新特性基于Perl 5.10及以上版本,部分实例摘录或改编自Learning Perl, 5ed。

简洁愉快的say(实用性:3星)

say "Hello, world";

等同于

print "Hello, world\n";

自动添加换行符,也许很不起眼的一个新函数,但是减少了按键次数。

 

直观的正则表达式命名捕捉(实用性:3星半)

以往,我们使用perl的内置变量$1,$2...来记录正则表达式的匹配内容,e.g.
my $line = "Symbol:AGO1 Chromosome:2R";
if($line =~ /Symbol:(\w+)\s*Chromosome:(\w+)/) {
say "Gene $1 is on chromosome $2!";
}

如果变量在后续部分还要使用,会使程序易读性下降;重新赋值于新变量又使得程序无端多了两行;于是,懒惰的程序员可以使用命名捕捉了:
my $line = "Symbol:AGO1 Chromosome:2R";
if($line =~ /Symbol:(?\w+)\s*Chromosome:(?\w+)/) {
say "Gene $+{gene} is on chromosome $+{chr}!";
}

所以可以看出,?的捕捉方式,实际上是把括号内匹配的内容存储在%+这样一个奇怪的哈希里了。所以要调用捕捉的内容,用$+{name}即可了!虽然看起来很诡异,但是在大的程序块里会相当好用噢。

同样,对于反向引用\1,\2,同样可以采用命名捕捉方式,例如,可以把以下代码
my $line = "Symbol:AGO1 Chromosome:2R Location:2R:9,834,047..9,845,594";
if($line =~ /Symbol:(\w+)\s*Chromosome:(\w+).*(\2:[.,\d]+))/ {
say "The location of Gene $1 is $3!";
}

更替为
my $line = "Symbol:AGO1 Chromosome:2R Location:2R:9,834,047..9,845,594";
if($line =~ /Symbol:(\w+)\s*Chromosome:(?\w+).*(\g{chr}:[.,\d]+))/ {
say "The location of Gene $1 is $3!";
}

即用\g{name}代替\2咯,也可以用\k等效代替
my $line = "Symbol:AGO1 Chromosome:2R Location:2R:9,834,047..9,845,594";
if($line =~ /Symbol:(\w+)\s*Chromosome:(?\w+).*(\k:[.,\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吧 :)


阅读(2299) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~