学习Perl(2)
列表和数组
1)特殊的数组索引值
假如对索引值超过数组尾端的元素赋值,数组将会依需要自动扩大---只要有可用的内存配置给Perl,数组的长度是没有上限的。必要时,插入的元素会自动产生,并设成undef值。把$#name当成索引值的做法十分常见,还可以 从数组尾端往回计数“负数数组索引值”
2)列表直接量
(1,2,3,) (1,2,3) (1..100) ($a,17) (“fred”, “betty”) 几个示例
qw(quoted word)缩写
在Perl程序里,经常要建立简单的单词列表,这时可以使用qw简写,省去键入一堆额外引号的时间:qw/ fred betty / 界定符还可以是其他的,如!、{、<、[等
在qw列表中,不能像双引号内的字符串一样使用n或$fred;因为qw是一种引号,所以不能将注释放在qw列表中。
3)列表的赋值
因为列表是在赋值运算开始之前建立的,所以在Perl里互换两个变量的值相当容易:
($fred,$betty) = ($betty,$fred); #互换两者的值
引用整个数组时,只要在数组之前加上一个@符号(而且后面没有出现索引的方括号)就可以了,如:@rocks = qw/ bedrock slate / ;
pop和push操作符:把数组当成堆栈来用是很常见的做法,这时,项目的新增和移除都是在右手边进行的(就是数组里位于“最后面”的那一端)。
pop操作符可用来取出数组中最后一个元素并且将它返回:
@array = 5..9; $fred = pop(@array); #$fred变成9,@array现在变成(5,6,7,8)
如果数组是空的,那么pop不会变动它,而且会返回undef。
push操作符和pop相反,它会添加一个元素或者一串元素到数组的尾端:push(@array,0);
注意:push的第一个参数或pop的唯一参数必须是数组变量,对列表直接量进行push或pop操作是毫无意义的。
shift和unshift操作符:对数组的“开头“进行相应的操作:
和pop类似,对于一个空的数组变量,shift会返回undef。
4)foreach控制结构
foreach循环会逐项处理列表的值,每次对一个值执行循环里的操作:
#!/usr/bin/perl -w
foreach $rock (qw/ bedrock slate lava /) {
print "One rock is $rock.n";
}
改进后Perl所支持的做法:
#!/usr/bin/perl -w
@rocks = qw/ bedrock slate lava /;
foreach $rock (@rocks) {
$rock = "t$rock";
$rock .= "n";
}
print "The rocks are:n", @rocks;
Perl最爱的默认变量$_
假如你在foreach循环的开头省略了控制变量,Perl会使用它最爱的默认变量$_:
#!/usr/bin/perl -w
foreach (1..10) {
print "I can not count to $_!n";
}
#!/usr/bin/perl -w
$_ = "Yabba dabba doon";
print;
reverse操作符:reverse会读取列表的值(可能来自数组)并依相反的次序返回该列表
#!/usr/bin/perl -w
@fred = 6..10;
@fred = reverse @fred;
print "The freds now are: @fred.n";
注意:reverse操作符会返回次序相反的列表,但它并不会影响自己的参数,所以假如返回值没有被赋值到任何地方,它将毫无意义:
reverse @fred ; #错:不会改变@fred @fred = reverse(@fred); #好多了
类似reverse的操作符sort,排序的顺序就是ASCII编码的顺序
对数组排序时,必须将排序的结果存回数组:@rocks = sort @rocks;
#!/usr/bin/perl -w
@fred = 97..102;
@fred = sort @fred;
print "The freds now are: @fred.n";
5)标量上下文与列表上下文
“上下文”指的就是表达式所出现的位置。解析表达式时,Perl会希望它是“标量值”或“列表值”的其中之一,此处,Perl所希望的,就称为表达式的上下文。
在Perl中,表达式的返回值一定会符合它们的上下文。以数组的“名称”为例:在列表上下文中,它会产生元素的列表;在标量上下文中,它会返回数组中元素的个数:
@people = qw( fred barney betty );
@sorted = sort @people; #列表上下文: barney betty fred)
@number = 42 + @people; #标量上下文:42 + 3等于45
@list = @people; #包含3个人名的列表
$n = @people; #数字3
#!/usr/bin/perl -w
@people = qw( fred barney betty );
@sorted = sort @people;
@number = 42 + @people;
@list = @people;
$n = @people;
print "The number of people are : $n.n";
print "The list ; @list.n";
print "The number : @number.n";
printf "The sorted : @sorted.n";
注意:但请不要立刻得出结论,在标量上下文中一定会得到列表上下文中所返回元素的个数。
在标量上下文中使用产生列表的表达式
除非有人提出别的实现方式,否则sort在标量上下文中总是会返回undef。
在列表上下文中,reserve会返回反序过的列表;在标量上下文中,它则会返回反序过的字符串:
#!/usr/bin/perl -w
@backwards = reverse qw/ yabba dabba doo /;
print "The list of backwards are: @backwards.n";
$backwards = reverse qw/ yabba dabba doo /;
print "The scalar of backwards are: $backwards.n";
不要被只有一个元素的列表给骗了,($dino) = something;这个还是列表上下文。只要元素是赋值给列表的(不管元素的个数),它就是列表上下文。假如你将元素赋值给数组,它也还是列表上下文。
在列表上下文中使用产生标量的表达式
这里的转换十分直接:假如表达式的求值结果不是列表值(也就是标量值),则标量值会被自动提升为含有单一元素的列表:@fred = 6 * 7; #变成含有单一元素的列表{42}
空列表的正确赋值法: @betty = (); 而不是:@betty = undef;
因为undef是标量值,所以将undef赋值给数组无法清空该数组。直接使用空列表赋值可能是比较好的办法。
@fred = 6 * 7;
print "The result of fred is : @fred.n";
@barney = " Hello" . ' ' . "world";
print "The result of barney is :@barney.n";
@betty = ();
print "The result of betty is : @bettyn";
强制指定标量上下文
有时候,需要在Perl期望列表上下文的时候,强制指定标量上下文,此时可以使用假函数scalar,它不是真的函数,只是用来告诉Perl必须提供标量上下文:
#!/usr/bin/perl -w
@rocks = qw( talc quartz jade obsidian );
print "How many rocks do you have?n";
print "I have ",scalar @rocks," rocks!n";
print "I have ", @rocks," rocks!n"; #错,这会输出各种石头的名称
列表上下文中的
输入数据的来源是键盘时,产生文件结尾符号的方式:UNIX及其类似的系统,键入Ctrl + D、对于DOS和Windows之类,键入Ctrl + Z。
@lines =
或者更简洁的 chomp(@lines =
习题:
1)读入一串字符串(每行一个),直到文件结尾为止,然后以相反顺序输出这个列表。(如果输入来自键盘,键入Ctrl + D或Ctrl + Z来结束输入)
#!/usr/bin/perl -w
print "Please enter a tring,each line for one:n";
print "When you finished it,please enter Ctrl + Dn";
chomp(@lines =
@lines = reverse @lines;
print "The result is ; @lines.n";
参考答案如下:
#!/usr/bin/perl -w
print "Enter some lines,then press Ctrl-D:n";
@lines =
@reverse_lines = reverse @lines;
print @reverse_lines;
或 #!/usr/bin/perl -w
print "Enter some lines,then press Ctrl-D:n";
print reverse
2
#!/usr/bin/perl -w
print "Please enter some numbers,each line for one,then enter Ctrl + D:n";
@names = qw / fred betty dino wilma pebbles bamm-bamm /;
chomp(@values =
foreach (@values) {
print "$names[$_ -1 ]n";
}
参考答案如下:
#!/usr/bin/perl -w
print "Please enter some numbers,each line for one,then enter Ctrl + D:n";
@names = qw / fred betty dino wilma pebbles bamm-bamm /;
chomp(@values =
foreach (@values) {
print "$names[$_ -1 ]n";
}
3)
#!/usr/bin/perl -w
print "Pleas enter lines,each line for one string,then enter Ctrl + D:.n";
print sort(
#!/usr/bin/perl -w
chomp(@lines =
@sorted = sort @lines;
print "@sortedn";
让每一行分开显示的做法: print sort
1)定义子例程
定义你自己的子例程时,将会用到关键字sub、子例程的名称(不含&符号)以及(花括号内)经缩排的构成子例程主体的程序代码块:(子例程的定义可以放在程序中的任何地方)
#!/usr/bin/perl -w
sub marine {
$n += 1;
print "Hello,sailor number $n!n";
}
2)调用子例程
任何表达式中只要使用了子例程的名称(加上&符号),就会调用子例程:&marine;
3)返回值
在Perl中,任何子例程都有返回值,子例程并没有分成有返回值和没有返回值两种。
#!/usr/bin/perl -w
sub sum_of_fred_and_barney {
print "Hey,you called the sum_of_fred_and_barney subroutine!n";
$fred + $barney;
}
$fred = 3;
$barney = 4;
$c = &sum_of_fred_and_barney;
print "$c is $c.n";
$d = 3 * &sum_of_fred_and_barney;
print "$d is $d.n";
sub larger_of_fred_and_barney {
if ($fred > $barney){
$fred;
} else {
$barney;
}
}
$fred = 3;
$barney = 4;
$c = &larger_of_fred_and_barney;
print "The larger is $c.n";