Perl语言入门笔记 第十七章 高级perl技巧(eval, grep, map)

切片:
    my (undef, $card_num, undef, undef, undef, $count) = split /:/;
    定义undef的话,会默认忽略匹配的变量
    更好的方法:
        列表切片
            my $mtime = (stat $some_file)[9]; #取得文件的第10个属性
    my $card_num = (split /:/)[1];
    my $count = (split /:/)[5];
    一次获得两个值:
        my ($card_num, $count) = (split /:/)[1, 5]; #取出1,5
        
    从列表中取出第一个和最后一个元素,借助索引-1代表最后一个元素这一事实:
        my ($first, $last) = (sort @names)[0, -1];
        
        my @numbers = (@names)[9, 0, 2, 1, 0];

数组切片:
    切片总是一个列表,所以数组切片总是使用一个@符号来标示,当你看见类似@names[...]之类的写法时,需要以perl的习惯来看开头的符号和结尾的方括号,方括号意味着你要检索数组成员,@符号则意味着获取的是整个列表,而$符号意味着获取单个元素。

    但有一个切片可以工作,列表却不能的场合,那就是切片可以被直接内插到字符串中去:
        my @names = qw{zero one three four five six seven eight nine};
        print "Bedrock @names[9, 0, 2, 1, 0]";
    如果我们想要内插@names,就会得到数组所有成员构成的字符串,元素之间用空格隔开,如果我们要内插的是@names[9, 0, 2, 1, 0], 就会得到指定数组元素构成的字符串,同样用空格隔开,让我们回到Bedrock图书馆的例子,假设我们的程序需要修改读者Slate先生的地址和电话号码,因为他刚刚搬到了Hollyrock山庄的某间大房子,如果我们得到一个存有关于他的信息列表的@items,那么就可以按如下方式简单的修改数组中的那两个元素:
        my $new_home_phone = "555-6099";
        my $new_address = "99380 Red Rock West";
        @items[2, 3] = ($new_address, $new_home_phone);        
哈希切片:
    和数组切片相似,也可以用哈希切片(hash slice)的方式从哈希里切出一些元素,还记得三个选手的保龄球积分吗?她们存放在哈希%score中,我们可以用哈希元素所构成的列表来取出这些积分,或是使用切片,这两个技巧实际效果相当,但第二种做法更加简洁高效:
        my @three_scores = ($score("barney"), $score{"fred"}, $score{""dino});
        my @three_scores = @score{qw/barney fred dino/};        
切片一定是列表,因此哈希切片也是用@符号来标示。
        my @player = qw(barney fred dion);
        my @bowling_scores = (195, 205, 30);
        @sorce{@player} = @bolwing_socres;
        
        哈希切片也可以被内插进字符串:
            print "Tonight's Player were: @players\n";
            print "Their scores were: @score{@players}"; 
            
捕获错误:
    用eval:
        检查运行时错误,用eval包起来
        eval{$barney = $fred / $dino};        
        现在即使是$dino为0也不会造成程序崩溃
        eval的返回值就是运距块中最后一条表达式的执行结果,常这样写:
            my $barney = eval {$fred / $dino};
            print "I couldn't divie by \$dino:$@" if $@;
        
        unless(eval{$fred / $dino})
        { print "I couldn't divide by \$dino: @$" if @!; }
        
        总共有4种类型的错误是eval无法捕获的:
            第一种:是出现在源代码中的语法错误,比如没有匹配的引号,忘写分号,漏写操作符,或者非法的正则表达式等。
            第二种:是让perl解释器本身崩溃的错误,比如内存溢出或者受到无法接管的信号。
            第三种:是eval无法捕获的错误是警告,不管是由用户发出的(通过warn函数),还是perl自己内部发出的(通过打开-W这个命令行选项,或者使用use warning编译指令。要让eval捕获警告专门的一套机制,请参考perl文档中_WARN_伪信号相关的内容)
            第四种:是exit操作符会立即终止程序运行,就算从eval块内部的子程序来调用它
            
为了安全不要在程序里用eval,只有在相当关注安全时才应该使用eval。
        任何出现在字符串中的东西都会被当做perl代码来解释执行:
            my $operator = 'unlink';
            eval "operator \@files";
            
            
更高级的错误处理:
    eval{ die "adfsasdfas"
          die "adfasd";;};
         
         
    Try::Tiny模块从CPAN下载:
        use Try::Tiny;
        try
        {
        }
        catch
        {
            
        }
        finally
        {
            这永远被执行到,以便实施清理工作
        }
        
        
autodie:
    use autodie;
    open my $fh, '>', $filename; #仍旧会在错误发生时调用die函数
    
    use autodie qw(open system:socket);

grep筛选列表:
    得到奇数:
        my @odd_numbers = grep($_ % 2) 1..1000;
        
    从文件中取出包含fred的行:
        得到符合的行结果:
            my @matching_lines = grep{/\bfred\b/i}<$fh>;
            my @matching_lines = grep /\bfred\b/i, <$fh>;
        得到符合的行的数量:
            my $line_count = grep /\bfred\b/i, <$fh>;
            
这就是上下文不同得到结果不同的很好解释

用map把列表元素变形:
    my @data = (4.75, 1.5, 2, 1234, 6.456, 12345, 23.94);
    my @formatted_data = map {&big_money($_)} @data;
    
    my @formatted_lines
    
    map的结果可以当成其他函数的参数传递
        print "The money numbers are:\n";
        map {sprintf("%25s\n", $_)}@formatted_data;
        
    当然不用临时数组也是可以的;
        my @data = (4.75, 1.5, 2, 1234, 6.456, 12345, 23.94);
        print "The money numbers are:\n", map{sprintf("%25s\n", &big_money($_))}@data;
    简单点:
        print "Some powers of two are:\n",
            map "\t" . (2 ** $_) . "\n", 0..15;

更花哨的列表工具:
    List::Util模块包含在标准库中,它提供各式高效的常见列表处理工具,都是用c语言实现的。        
        简洁的:
            use List::Util qw(first);
            my $first_match = first{/\bPebbles\b/i}@characters;
            
            use List::Util qw(sum);
            my $total = sum(1..100); #得到总和500500
            
            use List::Util qw(max);
            my $max = max(3, 5, 10, 4, 6);
            
            字符串的话:
                use List::Util qw(maxstr);
                my $max = maxstr(@strings);
                
            如果对列表中的元素随机排序的话,可以用shuffle实现:
                use List::Util qw(shuffle);
                my @shuffle = shuffle(1..1000); #使列表元素的排序随机
            
            不是CPAN自带的第三方模块:List::MoreUtils;
            use List::MoreUtils qw(none any all);
            if(none {$_ > 100}@numbers)
            { print "No elements over 100\n"; }
            elsif(any {$_ > 50}@numbers )
            { print "Some elements over 50\n"; }
            elsif(all {$_ < 10}@numbers )
            { print "All elements are less than 10\n"; }
            
            如果需要对按元素组处理列表的话,可以用natatime来取出对应位置上的元素:
                use List::MoreUtils qw(natatime);
                my $iterator = natatime 3, @array;
                while (my @triad = $iterator->())
                {    print "Got @triad\n"; }
                
    如果要合并两个或多个列表,可以用mesh构造一个大型列表,交错填充原始列表中各个位置上的元素,就算其中某个列表长度很小都没关系:
        use List::MoreUtils qw(mesh);
        
        my @abc = 'a' .. 'z';
        my @numbers = 1 .. 20;
        my @dinosaurs = qw(dino);
        
        my @large_array = mesh @abc, @numbers, @dinosaurs;    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值