Perl中级技巧

15 篇文章 2 订阅
12 篇文章 0 订阅

Perl中级技巧

1. 切片

列表、数组、哈希中往往包含很多信息,但是我们也许只需要其中的少量元素。假设Bedrock图书馆中用一个大文件来存放借阅者信息,文件的每一行都描述了一个读者,用6个字段(冒号:为分隔符)分别描述借阅者姓名、借书证号码、住址、住宅电话、工作电话和当前借阅数量。

  • 文件内容类似于:
    • fred flintstone:2168:301 Cobblestone Way:555-1212:555-2121:3
    • barney rubble:709918:299 Cobblestone Way:556-3333:555-2345:0
  • 图书馆的某个程序只需要借书证号码和借阅量,不关心其他数据。

1.1 列表切片

为了满足图书馆的程序需求,我们可以使用以下程序来读取需要的字段:

#!/usr/bin/perl
while (<$fh>){
	chomp;
	my @item = split /:/;
	my($card_num,$count) = ($item[1],$item[5]);             #@item中其他的数据没有用处,浪费存储空间。
}
#optimization 1
my($name,$card_num,$addr,$home,$work,$count) = split /:/;   #虽然省略了数组@item,但是引入了其他四个变量。
#optimization 2
my(undef,$card_num,undef,undef,undef,$count) = split /:/;   #使用undef占位,减少存储空间浪费,但是写法复
                                                            #杂,需要明确需要取出数据的准确位置
#optimization 3 (列表切片1)
my $card_num = (split /:/)[1];                #split的返回值是一个列表,因此可以使用列表的下标来获取数据
my $count = (split /:/)[5];                   #列表索引从0开始,因此最后一个变量的下标为5
my $count = split (/:/)[5];                   #语法错误。[n]索引之前的内必须包含在圆括号中,来表示列表上下文。
#optimization 3 (列表切片2)
my ($card_num,$count) = (split /:/)[1,5];     #可以在列表上下文中使用列表切片一次取得两个值,(推荐写法)
my @info = (split /:/)[1,2,3,1,5];            #切片下表可以是任意顺序,也可以重复

1.2 数组切片

如果我们希望从一个数组中获得少量数据,可以采用以下方式:

#!/usr/bin/perl
my @name_s = qw /dino barney fred link foopty/;
#使用数字切片时,可以省略圆括号,当我们看到 @some_array[....]就应该意识到这是数组切片
my @name = @name_s[1,2,3,1,3];       #perl中$表示取出单个东西,@意味着取出一组东西
my @name = @name_s[2,3];             #取出第三个和第四个元素
my @name = ($name_s[2],$name_s[3]);  #同上
#数组切片和列表切片对比:数组切片可以使用变量内插,列表切片不可以
print "names are @name_s[1,2,3,1].\n";    #语法正确,得到数组 @name_s中的四个变量,用空格隔开
print "naems are (split /:/)[1,2,3,1,5]"; #语法错误

1.3 哈希切片

如果我们希望从一个哈希中获得少量数据,可以采用以下方式:

#!/usr/bin/perl
my %score = {
	fred   => 96,
	barney => 90,
	loky   => 85,
};
#当看到 @hash{....}这样的代码,就要意识到这是哈希切片,得到是一些列value形成的列表
#哈希切片为什么不使用 %,因为在perl中%代表整个哈希,但是切片返回的类型应该是列表,因此使用@
my @three_scores = ($score{"fred"},$score{"barney"},$score{"loky"});
my @three_scores = @score{qw /fred banney loky/};   #切片一定是列表,因此哈希切片也使用 @ 符号
#可以使用这种方式对哈希元素进行赋值,例如又来了三个运动员需要计分数
my @new_players = qw /thor stark captian/;
@score{@new_players} = (100,97,89);
#哈希切片也可以内插到字符串
print "names are @score{qw /thor stark captian/}.\n";

1.4 键-值切片

如果我们希望从哈希中获得key-value对数据,可以采用以下方式:

#!/usr/bin/perl
#未使用键-值切片,获得新的哈希
my @three_scores = @score{@new_players};
my %new_hash;
@new_hash{@mew_palyers} = @thress_scores;
#使用perl 5.20提供了新式语法,使用%返回新的哈希
#这里变量名前的符号并非表示变量类型,我们只是使用它指定提取数据的方式,这里的%表示按照key-value的方式返回
use v5.20;
my %new_hash = %score{@players};
#当然,也可以对数组变量这么操作,同时将数组下标当做哈希键返回
my %array_to_hash = %some_array[0,-1];   #这里从[]就可以看出some_array是数组,因为它使用方括号定义下标

2. 用grep筛选列表

有时候我们希望选出列表中的部分成员,比如选出奇数,或者筛选文件中提到Fred的行。

  • 使用方法:
    • grep { code block } @array;
      • 列表上下文中:grep操作符返回列表;
      • 标量上下文中:grep操作符返回符合过滤条件的元素个数;
      • 代码块中$_是占位变量,代码块对列表中的每个元素进行计算,并返回真假值
      • 代码块之后的是将要被筛选的元素列表;
      • grep对元素列表中的每个元素进行运算,像foreach一样;
      • 如果代码块返回结果为真,那么这个列表元素就会出现在grep返回的列表中;
  • 在grep的运行过程中,$_会轮流成为列表中的每个元素化名,和在foreach中一样,如果在grep的代码快中对$_进行修改,那么原始数据也会被修改。
#!/usr/bin/perl
my @odd_numbers;
foreach (1..1000){
	push @odd_numbers,$_ if $_ % 2;
}
#使用grep
my @odd_numbers = grep ($_ % 2) 1..1000;   #实现和以上相同的功能
my $odd_numbers = @odd_numbers;            #查看列表中共有多少奇数
#如果不关心符合条件的内容,只关心符合条件的元素数量:
my $odd_numbers = grep ($_ % 2) 1..1000;   #直接返回符合条件个数,这里返回500
#grep操作符也可以使用正则表达式从文件中找出匹配成功的行
my @match_lines = grep { /\bfred\b/i } <$fh>;
#如果grep中代码块只有一个表达式,那么可以省略花括号{},使用逗号代替
my @match_lines = grep /\bfred\b/i,<$fh>;

3. 用map把列表数据变形

如果我们需要按照一定格式输出列表信息,不希望修改原始数据,我们需要的只是用于输出的列表拷贝。

  • 使用格式:
    • map { code block } @array;
    • 代码块中$_是占位变量,代码块对列表中的每个元素进行计算,并返回该表达时实际计算的值
    • 代码块之后的是将要被筛选的元素列表;
  • 在map的运行过程中,$_会轮流成为列表中的每个元素化名,和在foreach中一样,如果在map的代码快中对$_进行修改,那么原始数据也会被修改。
#!/usr/bin/perl
my @data = (455,4.89,6.8768,1234567,19.25);
#传统做法
my @format_data;
foreach (@data) {
	push @format_data,big_money($_);    #调用子函数big_money进行数据格式转换
}
sub big_money{
	my $number = sprintf "%.2f",$_;
}
#使用map
my @format_data = map { big_money($_)} @data;    #代码块返回表达式计算得到的值
  • map 和 grep 返回结果是列表,所以可以直接把结果传递给其他函数作为参数。
#!/usr/bin/perl
#使用临时数组
print "The money numbers are:\n",
	map {sprintf ("%.2f\n",$_)} @format_data;
#不使用临时数组
print "The money numbers are:\n",
	map {sprintf ("%.2f\n",$_)} @data;
#和grep一样,如果map的代码块中也是一个简单地表达式,可以直接省略花括号,并使用逗号分隔
print "Some powers of two are:\n",
	map "\t".(2**$_)."\n",0..15;

perl学习笔记暂时告一段落,如果后续有想法在对博文进行更新。学习日期:2018.11.23-2019.01.11

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值