Perl学习记录(二)

第三章 列表与数组

列表(list)指的是标量的有序集合,而数组(array)则是存储列表的变量。在Perl里,这两个术语常常混用。不过更精确地说,列表指的是数据,而数组指的是变量。列表的值不一定要放在数组里,但每个数组变量都一定包含一个列表(即便是不含任何元素的空列表)。
数组或列表中的每个元素都是单独的标量变量,拥有独立的标量值。这些值是有序的,也就是说,从起始元素到终止元素的先后次序是固定的。数组或列表中的每个元素都有相应的整数作为索引,此数字从0开始递增,每次加1。所以数组或列表的头一个元素总是第0个元素。
因为每个元素都是独立不相关的标量值,所以列表或数组可能包含数字、字符串、
undef值或不同类型标量值的混合。不过最常见的,还是具有相同类型的一组元素,如
由书籍标题组成的列表(全都是字符串),或是由余弦函数值组成的列表(全都是数
字)。
数组和列表可以包含任意多个元素。最少的情况是没有任何元素,最多的情况则是把可
用的内存全部塞满。

访问数组中的元素

数组元素是以连续的整数来编号, 从0开始,之后的每一个元素依次加1:

$fred[0] = "yabba";
$fred[1] = "dabba";
$fred[2] = "doo";

数组(此例中为"fred")的名字空间和标量的名字空间是完全分开的。你可以在同一个程序里再取一个名为 f r e d 的 标 量 变 量 , P e r l 会 将 两 者 当 成 不 同 的 东 西 , 但 程 序 维 护 员 也 许 会 搞 混 , 所 以 尽 量 避 免 。 凡 是 能 够 用 fred的标量变量,Perl 会将两者当成不同的东西,但程序维护员也许会搞混,所以尽量避免。 凡是能够用 fredPerl西fred[2]这类标量变量的地方,也都可以使用像$fred这样的数组元素。

print $fred[0];
$fred[2] = "diddley";
$fred[1] .= "whatsis";

任何求值能得到数字的表达式都可以用作下标。假如它不是整数,则会自动舍去
小数,无论正负:

$number = 2. 71828;
print $fred[$number - 1]; #结果和print $fred[1]相同

假如下标超出数组的尾端,则对应的值将会是undef。这点和一般的标量相同,如果从来
没有对标量变量进行过赋值,它的值就是undef:

$blank = $fred[ 142_857 ]; #未使用的数组元素,会得到undef的结果
$blanc = $mel;  #未使用的标量$mel,也会得到undef的结果

特殊的数组索引

假如你对索引值超过数组尾端的元素进行赋值,数组将会根据需要自动扩大一只要有可用的内存分配给Perl,数组的长度是没有上限的。如果在扩展过程中需要创建增补元素,那么它们的默认取值为undef:

$rocks[0] = ' bedrock' ; #一个元.....
$rocks[1] = 'slate' ; #又一个.....
$rocks[2] = 'lava'; #再来一个.....
$rocks[3] = 'crushed rock'; #再来一个....
$rocks[99] = 'schist' ; #现在有95个undef元素

想要找出数组里最后一个元素的索引值。对正在使用的数组rocks而言,最后一个元素的索引值是$#rocks。但这个数字比数组元素的个数少1,因为还有一个编号为0的元素:

$end = $#rocks; # 99, 也就是最后一个元素的索引值
$number_of_rocks = $end + 1;  #正确,但后面会看到更好的做法
$rocks[ $#rocks ] = 'hard rock';  #最后一块石头

最后一个例子里,把$#name当成索引值的做法十分常见,提供了简写:
从数组尾端往回计数的“负数数组索引值”。超出数组大小的负数索引值是不会绕回来的。假如你在数组中有3个元素,则有效的负数索引值为-1 (最后一个元素)、-2 (中间的元素)以及-3 (第一个元素)。如果你用-4或者再往后的索引值,只会得到undef而不会绕回到数组尾部。实践中,似乎没有人会使用-1以外的负数索引值:

$rocks[-1 ] = 'hard rock'; #和上面最后一个例子相同,但更简单
$dead_rock= $rocks[-100]; # 得到' bedrock'
$rocks[ -200 ] = ' crystal'; #严重错误!

列表直接量

列表直接量(程序代码中表示一列数据的写法),可以由圆括号内用逗号隔开的一串数据表示,而这些数据就称为列表元素。

(1, 2, 3) #包含1、2、3这三个数字的列表
(1, 2, 3,) #相同的三个数字(末尾的逗号会被忽略)
("fred", 4.5) # 两个元素,"fred"和4.5
() #空列表-- 0个元索
(1..100) # 100个整数构成的列表

… 范围操作符。该操作符会从左边的数字计数到右边,每次加1,以产生一连串的数字。

(1..5) #与(1, 2, 3, 4, 5)相同
(1.7..5.7) #同上,但这两个数字都会被去掉小数部分
(5..1) #空列表一一..只能向上计数
(02..6,1012) #同(0,2,3,4,5,6,10,12)
($m..$n) #范围由辆和$n当前的值来决定
(0. . $#rocks) #上节的rocks数组里的所有索引数字

数组中的元素不必都是常数一它们可以是表达式, 每次用到这些直接量时都会被重新计算。

($m, 17) #两个值: $m的当前值以及17
($m+$0, $p+$q) #两个值
#当然,列表可以包含任何标量值,像下面这个典型的字符串列表:
("fred", "barney", "betty", "wilma", "dino")

qw简写
需要建立简单的单词列表(如同前面的例子)。这时只需使用qw简写,就可以省去键入许多无谓引号的麻烦:‘

qw( fred barney betty wi1ma dino ) #同上,但更简洁,也更少击键

qw表示“quoted word (加上引号的单词)”,会将其当成单引号内的字符串来处理(在qw构建的列表中,不能像双引号内的字符串一样使用\n或$fred)。其中的空白符(如空格、制表符以及换行符)会被抛弃,然后剩下的就是列表的元素。

qw(fred
barney
betty
wilma dino) #同上,但空白符的用法比较奇怪

不能将注释放在qw列表中。有些人喜欢令每个元素单独成行,这样就能排成一列,查看和增删都非常方便:

qw(
fred
barney
betty
wilma
dino
)

除了以一对圆括号作为定界符,常用的写法有:

qw! fred barney betty wi1ma dino !
qw/ fred barney betty wilma dino /
qw# fred barney betty wilma dino #  # 看起来像是注释!
qw( fred barney betty wilma dino )
qw{ fred barney betty wilma dino}
qw[ fred barney betty wilma dino]
qw< fred barney betty wilma dino >

如果你需要在被圈引的字符串内使用定界符,那就说明你选错了定界符。不过,在你无
法或不希望更换定界符的情况下,还是可以通过反斜线转义来引人这个字符的:

qw! yahoo\!google ask msn!  #将yahoo!作为一个元素包含进来

和单引号内的字符串一样,两个连续的反斜线表示一个实际的反斜线:

qw( This as a \\ real backslash );

有谁会需要那么多不同的定界符呢?比如,如果需要构造一连串的Unix文件名的列表,换作其他定界符就方便多了:(如果只能以/作为定界符,那么文件路径就会充斥着转义斜线,这个列表会变得相当臃肿难读,并且将来的维护和修改都会很麻烦。)

qw{
/usr/dict/words
/home/ rootbeer/ . ispell _english
}

列表的赋值

就像标量值可被赋值给变量一样,列表值也可被赋值给变量:

($fred, $barney, $dino) = ("flintstone""rubble", undef);

左侧列表中的三个变量会依次被赋予右侧列表中对应的值,相当于我们分别做了三次独
立的赋值操作。因为列表是在赋值运算开始之前建立的,所以在Perl里互换两个变量的
值相当容易:

($fred, $barney) = ($barney, $fred); #交换这两个变量的值
($betty[0], $betty[1]) = ($betty[1], $betty[0]);

可是如果(在等号左边的)变量的个数不等于给定的列表值(来自等号右边)的个数
时,会发生什么情况呢?对列表进行赋值时,多出来的值会被悄悄忽略。另一种情况,如
果变量的个数多过给定的列表值的个数,那么那些多出来的变量将会被设成undef:

($fred, $barney) = qw< flintstone rubble slate granite >; #忽略掉末尾两个元素
($wi1ma, $dino) = qw[flintstone]; # $dino的值 为undef

明白了列表赋值,你便可以用如下代码来构建一个 字符串数组:

($rocks[0], $rocks[1], $rocks[2], $rocks[3]) =qw/talc mica feldspar quartz/;

当你希望引用整个数组时,在数组名之前加上@字符(后面没有检索用的方括号)。@rocks可以读作“所有的rocks”。

@rocks = qw/ bedrock slate lava /;
@tiny=();#空列表
@giant= 1..1e5; .#包含100 000个 元素的列表
@stuff = (@giant, undef, @giant);#包含200 001个元素的列表
$dino= "granite";
@quarry = (@rocks, "crushed rock" , @tiny, $dino);

将某个数组复制到另一个数组时,仍然算是列表的赋值运算,只不过这些列表是存储在数组里而已。

@copy = @quarry; #将一个数组中的列表复制到另一个数组

pop和push操作符
我们常把数组当成堆栈(stack) 来用,比如在数组列表右侧添加新值或者删掉旧值。数组中最右侧的便是最后一个元素,也就是拥有最大索引值的那个元素。因为我们常常要对这个元素
进行操作,所以Perl提供了专门的函数。pop操作符就是其中一个,它负责取出数组中最后一个元素并将其作为返回值返回:

@array = 5..9;
$fred = pop(@array); # $fred 变成9, @array 现在是(5, 6, 7, 8)
$barney = pop @array; # $barney变成8, @array 现在是(5, 6, 7) .
pop @array; # @array现在是(5, 6)。(7被抛弃了。 )

最后一行是在空上下文中使用pop操作符。所谓的“空上下文”只不过是表示返回值无处可去的一种说辞。这其实也是pop操作符常见的一种用法,用来删除数组中的最后一个元素。
如果数组是空的,pop什么也不做(因为没有任何元素可供移出),直接返回undef。
pop后面加不加括号都可以。
与此对应的是push操作符,用于添加一个元素(或是一串元素)到数组的尾端:

push(@array, 0); # @array现在是(5, 6, 0)
push @array, 8; # @array现在是(5, 6, 0, 8)
push @array, 1..10; # @array得到了10个新元索
@others=qw/90210/;
push @array, @others; # @array又得到了5个新元素(共19个)

shift和unshift操作符
unshift和shift操作符则是对数组的“开头”)进行相应的处理。

@airray = qw# dino fred barney #;
$mm= shift(@arrayi); # $mm变成"dino", @array现在是 ("fred" , "barney")
$nn=shift @airray;# $nn变成"fred", @array现在是("barney" )
shift @array;#现在@array变空了
$o = shift @array;# $o变成undef, @array还是空的
unshift(@array, 5);# @array现在仅包含只有一个元素的列表(5)
unshift @array, 4;# @array现在是(4, 5)
@others = 1..3;
unshift @array, @others; # @array 又变成了(1,2,3,4, 5)

splice操作符
添加或移除数组中间的某些元素,使用splice操作符。它最多可接受4个参数,最后两个是可选参数。
第一个参数当然是要操作的目标数组,第二个参数是要操作的一组元素的开始位置。如果仅给出这两项参数,Perl会把从给定位置开始~直到末尾的全部元素取出来并返回:

@array = qw( pebbles dino fred barney betty );
@removed = splice @array, 2; 
#在原来的数组中删掉fred及其后的元素# @removed变成qw(fred barney betty)
#而原先的@array则变成qw(pebbles dino)

第三个参数指定要操作的元素长度。

@array=qw( pebbles dino fred barney betty );
@removed=splice @array, 1, 2;
#删除dino和fred这两个元素
# @removed变成qw(dino fred)
#而@array则变成qw(pebbles barney betty)

第四个参数是要替换的列表。

@array=qw( pebbles dino fred. barney betty );
@removed=splice @array, 1, 2, qw(wilma); #删除dino 和fred
# @removed 变成qw(dino fred)
# @array变成qw(pebbles wilma barney betty)

添加元素列表并不需要预先删除某些元素,把表示长度的第三个参数设为0。即可不加删除地插入新列表:

@array = qw( pebbles dino fred barney betty );
@removed = splice @array, 1, 0, qw(wilma); 
#什么元素都不删
# @removed 变为qw()
# @array 变为qw(pebbles wilma dino fred barney betty)
#wilma出现在dino之前的位置上

字符串中的数组内插

数组的内容同样可以被内插到双引号串中。内插时,会在数组的各个元素之间自动添加分隔用的空格:

@rocks = qw{ flintstone slate rubble };
print "quartz @rocks limestone\n"; # 打印5种以空格隔开的石头名

数组被内插后,首尾都不会增添额外空格;若你真的需要,自己动手加吧:

print "Three rocks are: @rocks. \n";
print "There's nothing in the parens (@empty) here. \n";

要是你忘记了数组内插是这样写的,那么当你把电子邮件地址放进双引号内时,可能会
大吃一惊:

$email = "fred@bedrock.edu"; # 错!这样会内插@bedrock 这个数组

要规避这种问题,要么将@转义,要么直接用单引号来定义字符串:

$email = "fred\@bedrock.edu"; #正确
$email = ' fred@bedrock.edu'; # 另一种写法,效果相同

内插数组中的某个元素时,会被替换成该元素的值,正如你所愿:

@fred = qw(hello dolly);
$yy=2
$x = "This is $fred[1]'s place"; #得"This is dolly's place"
$x = "This is $fred[$yy-1]'s place"; #效果同上

索引表达式会被当成普通字符串表达式处理。该表达式中的变量不会被内插。假如$y包含字符串"2*4",索引结果仍然为1,而非7。
如果要在某个标量变量后面接着写左方括号,你需要先将这个方括号隔开,它才不至于被识别为数组引用的一部分

@fred = qw(eating rocks is wrong);
$fred = "right" ; #我们想要说"this is right[3]
print "this is $fred[3]\n"; # 用到了$fred[3],打印"wrong"
print "this is ${fred}[3]\n"; #打印"right" (用花括号避免歧义)
print "this is $fred" . "[3]\n"; #还是打印right (用分开的字符串)
print "this is $fred\[3]\n";#还是打印right (用反斜线避免歧义)

foreach控制结构

如果能对整个数组或列表进行处理将是非常方便的,Perl提供了另一种控制结构。
foreach (循环)能逐项遍历列表中的值,依次迭代(循环过程) :

foreach $rock (qw/ bedrock slate lava /) {
     print "One rock is $rock.\n"; # 依次打印所有三种石头的名称
}

每次循环迭代时,控制变量(control variable,即此例中的$rock)都会从列表中取得
新的值。第一次执行时,控制变量的值是"bedrock";而第三次时,控制变量的值是
“lava”。
控制变量并不是列表元素的复制品,它就是列表元素本身。也就是说,假如在循环中修改了控制变量的值,也就同时修改了这个列表元素

@rocks = qw/ bedrock slate lava /;
foreach $rock (@rocks){
$rock = "\t$rock";#在@rocks的每个元素前加上制表符
$rock .= "\n";#同时在末尾加上换行符
}
print "The rocks are:\n", @rocks; #各自占一行,并使用缩排

当循环结束后,控制变量的值会变成循环执行之前的值。在循环执行期间,我们无法访问或
改变已存储的值,所以当循环结束时,变量仍然保持循环前的值;如果它之前从未被赋
值,那就仍然是undef:

$rock = 'shale' ;
@rocks = qw/ bedrock slate lava /;
foreach $rock (@rocks) {
}
print "rock is still $rock\n"; #打印"rock is still shale"

最喜欢用的默认变量: $ _
假如在foreach循环开头省略控制变量,PerI就会用它最喜欢用的默认变量$_。

foreach (1..10) { #默认会用$_作为控制变 量
print "I can count to $_ !\n";
}

当未告知Perl使用哪个变量或数值时,Perl都会自动使用$,在没有参数时,它会打印
$
的值:

$_ . = "Yabba dabba doo\n";
print; # 默认打印$_变量的值

recerse操作符
reverse操作符会读取列表的值(也可能来自数组),并按相反的次序返回该列表。

@fred= 6..10;
@barney = reverse(@fred); # 得10, 9, 8, 7, 6
@wilma=reverse 6..10;#同上,但不需要额外的数组
@fred= reverse @fred;#将逆序后的结果放回原来那个数组

reverse会返回次序相反的列表,但它并不会修改传进来的参数。假如返回值无处可去,那这种操作也就变得毫无意义:

reverse @fred;#错误,这不会修改@fred的值
@fred = reverse @fred; #这才正确

sort操作符
sort操作符会读取列表的值(可也能来自数组),而且会根据内部的字符编码顺序对它们进行排序。大写字符排在小写字符前面,数字排在字母之前,而标点符号则散落各处。在第十四章里,我们将会看到如何按自定规则进行排序。sort操作符的参数应该是某个输入列表,然后对它排序,继而返回排序后的列表。来看几个例子:

@rocks = qw/ bedrock slate rubble granite /;
@sorted = sort(@rocks); #得bedrock, granite, rubble, slate
@back=reverse sort @rocks; #逆序后从slate到bedrock排列
@rocks= sort @rocks;# 将排序后的结果存回至@rocks
@numbers=sort 97..102; /#得100, 101, 102, 97, 98, 99

它和reverse一样不会修改参数,所以要对数组排序时,你必须将排序后的结果存回数组:

sort @rocks;#错误,这么做不会修改@rocks
@rocks = sort @rocks; #现在收集来的石头排得井井有条

each操作符
每次对数组调用each,会返回数组中下一个元素所对应的两个值:该元素的索引以及该元素的值:

use 5.012;
my @rocks = qw/ bedrock slate rubble granite /;
while( my( $index, $value ) = each @rocks ) {
say "$index: $value";
}

如果不用each来实现,就得自己根据索引从小到大依次遍历,然后借助索引值取得元素
的值: .

@rocks
= qw/ bedrock slate rubble granite /;
foreach $index ( 0.. $#rocks ) {
print "$index: $rocks[$index]\n" ;
}

标量上下文与列表上下文

这是本章最重要的一节,这甚至也是本书最重要的一节。你的Perl水平完全取决于对本节的了解程度。
这里的概念其实非常简单:同一个表达式出现在不同的地方会有不同的意义。
以英语为例,假如有人问你单词“read”代表什么意思,你一定很难简单回答,因为用在不一样的地方,表达的意思可能会不同。除非你知道上下文,否则一定没办法确认它的准确含义。
所谓上下文,指的是你如何使用表达式。实际上你已经看到过许多针对数字和字符串上
下文的操作了。比如按照数字方式进行操作时得到的就是数字结果,而按照字符串方式
进行某些操作时返回的则是字符串结果。并且,起到决定性因素的是操作符,而不是被
操作的各种变量或直接量。23中的作为对数字的乘法运算符号时得到的结果就是数字
6,而<2x3>中的x则表示字符串重复操作,所以得到的结果是字符串222。这就是上下文
在起作用。
当Perl在解析表达式时,你要么希望它返回一个标量, 要么希望它返回一个列表。表达式所在的位置,Perl期望得到什么,那就是该表达式的上下文:

42 + something #这里的something必须是标量
sort something #这里的something必须是列表

就算something这个单词的拼写保持不变,它却会在某种情况下得出单一的标量值, 而在
另外的情况下产生一个列表。在PerI中,表达式总是根据所需要的上下文返回对应的值。以数组的“名称”为例,在列表上下文中,它会返回元素的列表;在标量上下文中,则返回数组中的元素个数:

@people = qw( fred barney betty );
@sorted = sort @people; # 列表上下文: barney, betty, fred
$number = 42 + @people; # 标量上下文:42 + 3,得45

即使是普通的赋值运算(对标量或列表赋值),都可以有不同的上下文:

@list = @people; #得到3个人的姓名列表
$n=@people;#得到人数3

但请不要立刻得出结论,认为在标量上下文中一定会得到(列表上下文中返回的列表的)元素个数。有许多能产生列表的表达式所返回的东西可能比你想象中的还要丰富有趣。.
不光如此,从我们积累的经验来看,仅仅通过对表达式形式上的判断是无法归纳出一个通用法则来的。每一个表达式都可能有它自己的特定规则。所以,实际上能够概括的规则也就是:哪种上下文更有意义,就应该是哪种上下文。但其实记住这条规则并没什么用。Perl是一种会尽量帮你完成常见任务的语言,往往它的选择就是你想要的结果。

在标量上下文使用产生列表的表达式
有些表达式通常是用来生成列表的,假如在标量上下文中使用,结果会怎样?
某些表达式不会在标量上下文中返回任何值。
比如sort在标量上下文中会返回什么?实际上没人需要统计列表排序后的元素个数。所以,除非有人修改了实现方式,否则sort在标量上下文中总是返回undef.
另一个例子是reverse。在列表上下文中,它很自然地返回逆序后的列表;在标量上下文中,则返回逆序后的字符串(先将列表中所有字符串全部连接到一起,再对结果中的每一个字符作逆序处理) :

@backwards = reverse qw/ yabba dabba doo /;#会得到doo, dabba, yabba
$backwards = reverse qw/ yabba dabba doo /;#会得到oodabbadabbay

刚开始时,往往很难一眼看出某个表达式到底是在标量上下文还是在列表上下文中。但.相信我们,这种直觉终将成为你的第二天性。
作为起步,下面列出一些常见的上下文:

$fred = something;#标量上下文
@pebbles = something;#列表上下文
($wilma, $betty) =something; #列表上下文
($dino) = something;#还是列表上下文!

不要被只有一个元素的列表给蒙骗了,最后一个例子是列表上下文而不是标量上下文中。这里的括号非常重要,使得第四行和第一行完全不同。如果是给列表赋值(不管其中元素的个数),那就是列表上下文;如果是给数组赋值,那还是列表上下文。
下面列出的是之前看到过的表达式以及各表达式的上下文,我们分成两组,第一组是标量上下文中使用something的例子:

$fred = something ;
$fred[3] = something;
123 + something
something + 654
if (something) { ... }
while (something) { ... }
$fred[something] = something;

第二组是列表上下文中的例子:

@fred = something;
($fred, $barney) = something;
($fred) = something;
push @fred, something;
foreach $fred (something) { ... }

在列表上下文中使用产生标量的表达式
如果表达式求值结果为标量值,则自动产生一个仅含此标量值的列表:

@fred = 6 * 7; #得到仅有单个元素的列表(42)
@barney = "he1lo".' ' . "world";

好吧,其实这里有个小小的陷阱:

@wilma = undef; #糟糕!结果是得到一个列表,而且仅有的一个元素为未定义的(undef)
#这和下面的做法的效果完全不同:
@betty = ( );
#这才是正确的清空数组的方法.

因为undef是标量值,所以将undef赋值给数组并不会清空该数组。要清空的话,直接赋
予一个空列表就可以了

强制指定标量上下文
偶尔,在Perl想要列表上下文的地方你想要强制引入标量上下文,可以使用伪函数scalar。它可不是真正的函数,只不过告诉Perl这里要切换到标量上下文:

@rocks = qw( talc quartz jade obsidian );
print "How many rocks do you have?\n" ;
print "I have ", @rocks,rocks!\n";#错误,这会输出各种石头的名称
print "I have ",scalar @rocks,rocks!\n"; #对了,打印出来的是石头种数

没有相应的函数可用来强行切入列表上下文。原因很简单,因为你根本用不到。

列表上下文中的

我们之前看过的操作符在列表上下文中会返回不同的值.在标量上下文中会返回输入数据的下一行;在列表上下文中,则会返回所有剩下的行,直到文件结尾为止。返回的每一行都会成为列表中的元素。例如:

@lines = <STDIN>; #在列表上下文中读取标准输入

当输入数据来自某个文件时,它会读取文件的剩余部分。但如果输入数据的来源是键盘,应该如何发送文件结尾标记呢?对Unix或类似系统( 包括Linux和Mac OS X)来说,通常可以输入Control+D来告知系统,不会再有任何输入了。即使这个特殊字符会被打印在屏幕上,Perl也不会看到它。对DOS/Windows系统来说,就要用Control+Z了。
假如运行程序的人在键入了三行数据之后,又用适当的按键来表示文件结尾,最后得到的数组就会包含三个元素。每个元素都是一个以换行符结尾的字符串,因为这些换行符也是输入的内容。
如果在读取这些数据行时,能一次性chomp所有的换行符岂不更好?可以直接把数组交给chomp,它会自动去掉每个元素的换行符。例如:

@lines=<STDIN>; # Read all the lines
chomp(@lines);#去掉所有换行符

不过更常见的做法是按之前介绍的风格写成:

chomp(@lines = <STDIN>); #读入所有行,换行符除外

虽然你可以按个人喜好来决定怎么做,不过大多数Perl程序员都会倾向于第二种更紧凑
的写法。
输人数据一经读取,就无法回头再读一次。如果要读入的是某个400MB大小的日志文件,行输入操作符会读取所有的数据行,同时占用大量内存。Perl不会限制你做这种事,但是系统中的其他用很可能会抗议。在读取大量数据时,通常应该考虑替代方案,避免一次将全部数据读进内存。

习题

1.[6]写-一个程序,读入一些字符串(每行一个),直到文件结尾为止。然后,再以相反顺序输出这个列表。假如输入来自键盘,你需要在Unix系统上键入Control+D或在Windows系统上键入Control+Z来表示输人的结束。
1
最后一行使用了.连接,导致上下文为标量,得到结果输入字符的个数
1
用,连接,上下文为列表,输出字符倒序连接结果

参考答案:

print "Enter some lines, then press Ctrl-D:\n"; 
@lines = <STDIN> ;
@reverse_lines = reverse @lines;
print @reverse_ lines;
#更简单的写法:
print "Enter some lines, then press Ctrl-D: \n" ;
print reverse <STDIN>;
  1. [12]写一个程序, 读入一些数字(每行一个),直到文件结尾为止。然后,根据每一个数字输出如下名单中相应的人名(请将这份名单写到程序里,也就是说,你的程序代码里应该出现这份名单)。比方说,如果输人的数字是1、2、4和2,那么输出的人名将会是fred、betty、dino和betty:
    fred betty barney dino wilma pebbles bamm-bamm
    2
    两个问题:
    ①索引是从0~6,不知道如何把它改成1-7
    ②输出连了一块,不知道如何引入空格。

参考答案:

@names = qw/ fred betty barney dino wilma pebbles bamm- bamm /;
print' "Enter some numbers from 1 to 7, one per line, then press Ctr1-D:\n";
chomp(@numbers = <STDIN>);
foreach (@numbers) {
print "$names[ $_ - 1 ]\n";
}

另外一种做法是在@names数组前面加上一个值来充数,像这样:

@names = qw/ dummy_item fred betty barney dino wilma pebbles bamm-bamm /;
  1. [8]写一个程序,读入一些字符串(每行一个),直到文件结尾为止。然后,请按照ASCII码顺序输出所有字符串。换句话说,假如你键人的是fred. barney.wilma、betty, 输出应该显示barney betty fred wilma。 所有的字符串可以成一行输出吗?或者分开在不同行输出?你能分别让程序以这两种方式输出吗?
    3

参考答案:

chomp(@lines = <STDIN>);
@sorted = sort @lines ;
print "@sorted\n" ;
#或者,让每行分开显示:
print sort <STDIN>;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值