Perl语言入门14-17

---------第十四章 字符串与排序-------------------

index查找子字符串

my $stuff = "howdy world!";
my $where = index($stuff, "wor"); #6
#返回首个字符匹配的位置,字符串第一个位置为0,上例即wor匹配的w位置
#无法匹配返回-1

my $here = index($stuff,"w",2); #返回2(从2+1个字符开始)
my $there = index($stuff,"w",3); #返回6

rindex从末尾开始找起,基本用不到

substr操作子字符串

#第二个参数:起始位置,第三个参数:截取长度
my $minx = substr("fred J. Flintstone", 8, 5); #Flint

my $peb = substr "fred J. Flintstone", 13; #stone 不加第三个参数,默认到最后

my $out = substr("some very long string",-3,2); #in 倒数第三个字符开始

#与index结合使用
my $long = "some very very long string";
my $right = substr($long, index($long,"l"); #long string

#修改字符串
my $string = "hello, world";
substr($string, 0, 5) = "goodbye"; #goodbye, world  可见长度不一定相同

#替换
substr($string, -20) =~ s/fred/barney/g; #只替换字符串后20个中匹配字符

sprintf格式化字符串

不同于printf的是它能赋值给变量

my $date = sprintf "%4d %02d",$yr,$mo; 
my $money = sprintf "%.2f",2.3456;

排序

#数组排序
my @numbers = sort {$a <=> $b} @some_numbers; #数值
my @string = sort {$a cmp $b} @some_strings; #字符串

my @descending = reverse sort {$a <=> $b} @some_numbers;
my @descending = sort {$b <=> $a} @some_numbers; #结果同上

#哈希值排序
sort keys %hash #这是对键排序
sort{$hash{$b} <=> $hash{$a}} keys %hash #值排序,降序
sort{$hash{$a} <=> $hash{$b}} keys %hash #升序
#sort values %hash ???

#先按值再按键排序
my @winner = sort by_score_name keys %score;
sub by_score_name{
    $score{$b} <=> $score{$a} #根据分数降序排列
      or
    $a cmp $b  #分数相同再按名字排序
}
#飞船操作符返回-1或1,都为真,两数相同时返回0。
#再加or,可进行多级排序

-------第十五章 智能匹配与given-when结构------------

智能匹配操作符~~

会根据两边操作数的数据类型自动判断何种方式进行比较和匹配,一般与前后顺序无关,特殊情况外。

say "I found fred in the same" if $name ~~ /Fred/;

对不同操作数的处理:

%a ~~ %b #键是否相等
%a ~~ @b 或@a ~~ %b #a键是否在数组b中
%a ~~ /fred/ 或/fred/ ~~ %b  #键匹配
'fred' ~~ %a  #哈希值$a{fred}是否存在
@a ~~ @b #数组是否相同
@a ~~ /fred/ #数组中至少一个元素匹配
$name ~~ /fred/ #模式匹配
'fred' ~~ 'fred' #字符串是否相同
123 ~~ 456 #数组是否相等

示例1:%names中是否匹配fred键,若有打印

#传统写法:
my $flag = 0;
foreach my $key (keys %name){
    next unless $key =~ /fred/;
    $flag = $key;
    last;
}
print "the key is $flag\n" if $flag;

#智能匹配:
say "sucess" if %names ~~ /fred/; #或if /fred/ ~~ %names

示例2:判断两个等长的数组是否完全相同

#传统写法:
my $equal = 0;
foreach my $index (0..$#names1){
    last unless $names1[$index] eq $names[$index];
    $equal++;
}
print "yes\n" if $equal == @names1;

#智能匹配:
say "yes" if @names1 ~~ @names2;
  • given语句
    given-when多条件,类似c语言switch语句。
given ($ARGV[0]){
    when('fred'){say "1"} #实际是$_ =~    或$_ ~~
    when(/Fred/i){say "2"}
    when(/\AFred/){say "3"}
    default {say "4"}
}
#和if-elsif-else语句的区别在于:given-when可在满足某条件的基础继续测试其他条件,而if-else-elsif-else则非此即彼。
#每个条件也可加break/continue等控制

多个条目的when匹配

将given放到foreach中循环测试

foreach my $name(@names){
    given($name){
        ...
    }
}

##可简化以下形式:
foreach(@names){ #不使用具名控制变量
    say "\nProcessing $_";
    
    when('fred'){say "1"; continue}  #continue使每个条件都能执行
    when(/Fred/i){say "2"; continue}
    when(/\AFred/){say "3"}
    say "moving on to default...";
    default {say "4"}
}

----------第十六章 进程管理----------------------

system函数

perl程序为父进程,system为子进程。

#一般就是shell命令。
system 'date';

system 'ls -l $HOME'; 
#此处用双引号,会将$HOME视为变量内插,而非环境变量

system 'for i in *; do echo ==$i==; cat $i; done &';
#里面的命令为孙进程;&放后台运行,perl程序无需等待它运行完

#不使用shell命令,则用多参数:
system 'tar','cvf',$tarfile, @dirs;

环境变量

%ENV : 每个键都代表一个环境变量  
$ENV{'PATH'} = "/home/rootbeer/bin:$ENV{'PATH'}";

其他类system函数和命令

#1.exec函数
exec 'date';
#不能在后台运行,一般很少用

#2. 反引号
print "the time is now: ", `date`;
my $out_errors = `frobnitz -enable 2>&1`; #将标准错误合并至标准输出
#建议如果不需要捕获输出内容,就不要用反引号。

#3. qx操作符
qx(perldoc -t -f int) #近似反引号

#建议还是用system函数

------第十七章 高级Perl技巧-------------------

切片

#标量:
my $count = (split /:/)[5];
my($card,$count) = (split /:/)[1,5];
my($first, $last) = (sort @names) [0,-1] #取第一个和最后一个

#数组切片:
my @num = @names[9,2,1,0,1];
#下标可任意顺序,也可重复

#哈希切片:
my @three_scores = @score { qw/barney fred dino/ }
#等于:my @three_scores = ($score{"barney"}, $score{"fred"}, $score{"dino"});

my @name = qw /a b c/;
my @math_score = qw /1 2 3/;
@score{@name} = @math_score; #相当于构建哈希
print "their scores were: @score{@name}\n"; #也能内插

捕获错误

  • eval表达式
    检查到致命错误立即停止运行整个eval块,退出后继续运行其余代码。
    默认返回语句块最后一条表达式结果。若捕获到错误,整个语句块返回undef,并在特殊变量$@中设置错误消息。
#如对除0错误的处理:
my $barney = eval {$fred/$dino} // 'NaN'; #将NaN设为默认值
print "I can't divide by \$dino : $@" if $@;

#检查返回值来判断
unless (eval { $fred/$dino}){
    print "I can't divide by \$dino : $@" if $@;
}

#对多处潜在(打开文件/除0/子程序等)的致命错误做防范:
foreach my $person (qw /one wtow three four/){
    eval{
        open my $fh, '<', $person or die "can't open file: $!";
        my ($total, $count);
        while(<$fh>){
            $total += $_;
            $count++;
        }
        my $average = $total/$count; #eval也可在此嵌套
        print "average for file $person was $average\n";
        
        &do_something($person,$average);
    }
    if($@){
        print "an error occurred ($@),continuing\n";
    }
}

#但有些错误是eval无法捕获的:
#如语法错误;perl解释器崩溃;警告信息;exit操作符

高级错误处理

Perl语言处理错误的基本做法:用die抛出异常,用eval捕获异常,通过识别$@中的错误消息判断问题出在哪里。

#local $@;
eval{
    ...;
    die "a unexpected message" if $unexpected;
    die "bad denominator" if $dino == 0;
    $barney = $fred/$dino;
}
if( $@ =~ /unexpected/){...;}elsif($@ =~ /denominator/){...;}
#这类代码有很多弊端,如$@的动态作用域问题,确保不干扰高层eval错误。
#这里最好在最前加上local $@;


#Try::Tiny模块解决这类问题:
use Try::Tiny;
try{...;} #可能抛出异常的代码
catch{...;} #处理异常的代码
finally{...;} #不管是否出错都运行的代码

my $barney = 
    try{$fred/$dino}
    catch{say "error is $_";} #$_替代$@,避免干扰
    finally{say @_? 'error' : 'worked';}; #@_判断参数内容
    
    
#autodie:
#perl自带autodie编译指令,自动抛出异常
use autodie;
open my $fh, '>', $filename;

grep函数处理列表元素

返回真假值

my @odd_numbers = grep { $_ % 2} 1..1000; #挑出奇数

my @match_lines = grep {/\bfred\b/i} <$fh>;
my @match_lines = grep /\bfred\b/i/, <$fh>; 
#若只有一个表达式,可去掉大括号加逗号进行简化

my $line_count = grep /\bfred\b/i, <$fh>; #标量,返回匹配个数

map函数处理列表元素

返回实际结果

my @data = (4.5,6.23,67);
my @format_data = map {&big_money} @data; #对金额数字格式化
print "the money are: \n", map {sprintf("%25s\n", $_)} @format_data;

#简单表达式同样可简化:
print "some powers of two are:\n",
    map "\t".(2**$_)."\n", 0..15;

其他处理列表元素函数

Perl自带的List::Util模块

#first函数:
my $first_match = first {/\bfred\b/i} @names; 

#sum函数
my $total = sum(1..100);

#max函数
my $max = max(3,5,4,7);

#maxstr函数:最长字符串
my $max = maxstr(@strings);

#shuffle函数:对列表元素随机排序
my @shuffled = shuffle(1..1000);

List::MoreUtils模块

#none/any/all函数
if(none {$_>100} @numbers){...;} 
elsif(any {$_ >50} @numbers){...;}
elsif(all {$_ <10} @numbers){...;}

#natatime函数(n at a time,同时处理n组)
my $iterator = natatime 3, @array;

#mesh函数:合并多个列表(交错填充)
my @large_array = mesh @one, @two, @three;
posted @ 2019-06-02 13:24  生物信息与育种  阅读(432)  评论(0编辑  收藏  举报