设为首页 收藏本站
查看: 1112|回复: 0

[经验分享] Learning Perl 4ed Reading Notes

[复制链接]

尚未签到

发表于 2015-12-27 04:12:42 | 显示全部楼层 |阅读模式
1. List and Array.  本书中所讲的List是一种数据结构,Array是Perl中用来存放List的数据类型。大部分情况下,这两个单词可以互换,意思是一样的。和C不一样 的是,Perl的Array不用定义元素的类型,也就是说,Perl中的Array中的每个元素可以是Number,也可以是String,元素的类型没 必要都一样。和C相同的就是,对Array的访问都是通过下标进行的,第一个元素的数组下标是0。

2. Perl中的Array用起来和C中的没什么区别:

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

如果给定的下标不正确,那么将得到undef:

$blank = $fred[ 142_857 ]; # unused array element gives undef
$blanc = $mel;             # unused scalar $mel also gives undef

3. Special Array Indices. Perl中的Array有一个比较有意思的事情就是,如果访问的数组下标越界了(超过数组大小了),那么Perl不会出错,Perl会自动为我们将数组扩容:

$rocks[0]  = 'bedrock';      # One element...
$rocks[1]  = 'slate';        # another...
$rocks[2]  = 'lava';         # and another...
$rocks[3]  = 'crushed rock'; # and another...
$rocks[99] = 'schist';       # now there are 95 undef elements

上面的例子中,rocks这个数组最后就变成有100个元素了,中间有95个undef的元素。

4. 我们可以用$#rocks来取得数组最后一个元素的index值,比如$#rocks就会得到99,注意这个值实际比数组元素的个数要小1,因为第一个元素是从0开始的,$#rocks返回的是最后一个元素的index值,而不是数组大小
5. List Literals. 本节介绍用hard code的方式定义一个List。Perl定义一个List的方式非常灵活,如:

(1, 2, 3)      # list of three values 1, 2, and 3
(1, 2, 3,)     # the same three values (the trailing comma is ignored)
("fred", 4.5)  # two values, "fred" and 4.5
( )            # empty list - zero elements
(1..100)       # list of 100 integers

(1..5)            # same as (1, 2, 3, 4, 5)
(1.7..5.7)        # same thing - both values are truncated
(5..1)            # empty list - .. only counts "uphill"
(0, 2..6, 10, 12) # same as (0, 2, 3, 4, 5, 6, 10, 12)
($m..$n)          # range determined by current values of $m and $n
(0..$#rocks)      # the indices of the rocks array from the previous section
("fred", "barney", "betty", "wilma", "dino")

从上面的例子可以看到,定义List的时候也可以使用变量,这样的话,一个List的值就不完全是静态的了,也可以是动态的。

此外,注意,使用..的时候,只能是uphill的,也就是说(5..1)这样是不行的。后面会介绍reverse operator,可以把List中的内容翻转过来。

6. "qw" shortcut. qw是一个shortcut,意思是"quoted words" or "quoted by  whitespace",使用qw可以让我们快速的定义一个字符串List,使用qw的话,每个String可以不用引号,这样可以省略一些typing 的工作:

qw( fred barney betty wilma dino )
就等同于
("fred" "barney" "betty" "wilma" "dino")

而且非常不错的是,在Perl中用qw定义一个字符串List,delimiter可以自由选择:

qw! fred barney betty wilma dino !
qw# fred barney betty wilma dino #   # like in a comment!
qw( fred barney betty wilma dino )
qw{ fred barney betty wilma dino }
qw[ fred barney betty wilma dino ]
qw< fred barney betty wilma dino >

这里可以看到,不一定要用()来把字符串括起来,完全可以用其他的字符,只要保证两个delimiter是一对符号或是一样的char就可以。

但是需要注意的是,用qw申明的List Literals,每个字符串相当于是用单引号括起来的,所以不能在字符串中使用变量,很多用backslash的转义也不能使用。此外,如果我们的字符串中要包含delimiter本身的话,请用backslash转义:

qw! yahoo\! google excite lycos ! # include yahoo! as an element

能够使用多种多样的字符作为delimiter是非常不错的,比如:

Code: Select allqw{
  /usr/dict/words
  /home/rootbeer/.ispell_english
}

如上,我们要把一串UNIX的路径作为字符串,那么,就可以用非/的字符作为delimiter,如果Perl规定只能用/作为delimiter的话,那么上面的代码将会非常的不好读。。此外,为了方便,Perl还定义了一些特殊的数组下标,比如负值的数组index,最常用的就是-1,这表示数组的最后一个元素,所以下面两句代码效果是一样的:

$rocks[ -1 ]   = 'hard rock';
$rocks[ $#rocks ] = 'hard rock';

-2, -3...依次类推,不过一般我们只会用一个-1,其他的实用意义就不大了。  

  
7. List Assignment. 本节讲述如何给List赋值,注意这里讲的是List,不是Array。比如:

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

这样就可以给三个变量赋值,这三个变量就可以理解成组成了一个List,于是,我们可以这样很方便的交换两个变量的值而不用通过一个中间变量:

($fred, $barney) = ($barney, $fred); # swap those values
($betty[0], $betty[1]) = ($betty[1], $betty[0]);

当右边赋值的清单比左边的变量多了或是少了,会怎么样呢?很简单,值多了会被ignore,变量多了,多出来的变量将全部被赋成undef:

($fred, $barney) = qw< flintstone rubble slate granite >; # two ignored items
($wilma, $dino)  = qw[flintstone];     # $dino gets undef

注意上面的qw后面的<>,[]都是delimiter,没有什么其他的特别含义。

8. @ 符号。Perl提供了一个@符号,用来访问整个Array/List。比如:

@rocks  = qw/ bedrock slate lava /;
@tiny   = ( );                       # the empty list
@giant  = 1..1e5;                    # a list with 100,000 elements
@stuff  = (@giant, undef, @giant);   # a list with 200,001 elements
$dino   = "granite";
@quarry = (@rocks, "crushed rock", @tiny, $dino);

如上,使用@就可以访问整个Array,非常方便。所以,用@copy = @quarry; 就表示将数组quarry中的所有元素赋给copy数组。

9. pop and push Operators.  pop就是删除数组的最后一个元素并返回这个元素;push就是将一个元素加到数组的最后,数组长度加1。前面已经说了,用数组的index也可以做到这 一点(访问超过数组长度的index的时候Perl会自动为我们将数组扩展到这个大小,不会出错),为什么不用index,要专门发明pop和push 呢?很简单,第一,用push和pop更好理解;第二,用push和pop性能更高,因为在使用index的时候,特别是访问一个超过数组长度的 index的时候,Perl内部会触发异常,然后再处理这个异常,这中间做的事情很多,导致性能很低。所以,和C不一样,Perl中鼓励我们用push和 pop来操作数组末尾的元素。

@array  = 5..9;
$fred   = pop(@array);  # $fred gets 9, @array now has (5, 6, 7,
$barney = pop @array;   # $barney gets 8, @array now has (5, 6, 7)
pop @array;             # @array now has (5, 6). (The 7 is discarded.)

push(@array, 0);      # @array now has (5, 6, 0)
push @array, 8;       # @array now has (5, 6, 0,
push @array, 1..10;   # @array now has those 10 new elements
@others = qw/ 9 0 2 1 0 /;
push @array, @others; # @array now has those five new elements (19 total)

如果我们pop一个empty的array,那么将返回undef。

10. shift and unshift Operators. 和push、pop一样,不同的是shift/unshift操作的是数组开头的元素。

@array = qw# dino fred barney #;
$m = shift(@array);      # $m gets "dino", @array now has ("fred", "barney")
$n = shift @array;       # $n gets "fred", @array now has ("barney")
shift @array;            # @array is now empty
$o = shift @array;       # $o gets undef, @array is still empty
unshift(@array, 5);      # @array now has the one-element list (5)
unshift @array, 4;       # @array now has (4, 5)
@others = 1..3;
unshift @array, @others; # @array now has (1, 2, 3, 4, 5)

shift一个empty的array的时候,会返回undef。

11. Interpolating Arrays into Strings. 本节讲述在字符串中引用数组-当然是在双引号的字符串中。

@rocks = qw{ flintstone slate rubble };
print "quartz @rocks limestone\n";  # prints five rocks separated by spaces

很简单,用@符号就可以引用整个数组,用$array[index]引用数组中的一个元素。

这里插一句:再给list赋值的时候,默认都是用空格来分割各个元素,我们可以改变这一默认行为,和shell编程一样的,在Perl中,通过重定义$"就可以设定默认以什么字符为分隔符来区分list中的各个元素。

回过来,再引用整个数组的时候,打印出来的字符串前后都是没有空格的,所以,我们要手动在String中加入空格。

12.  前面看到了,我们用@符号引用了整个Array,那么,很自然会碰到的问题是,当我们的String是一个EMail地址的时候(含有@符号),那么,我 们要用backslash转义一下,否则Perl会认为我们在这个String中引用了一个数组,而不是一个EMail地址,如:

$email = "fred@bedrock.edu";  # WRONG! Tries to interpolate @bedrock
$email = "fred\@bedrock.edu"; # Correct
$email = 'fred@bedrock.edu';  # Another way to do that

13. 综述。看例子:

@fred = qw(hello dolly);
$y = 2;
$x = "This is $fred[1]'s place";    # "This is dolly's place"
$x = "This is $fred[$y-1]'s place"; # same thing

这里我们引用了数组中的一个元素,这里需要注意的是,$fred[$y-1]中,Perl 只会机械的将$y替换成2,如果这里的$y=2*4,那么Perl也只会机械的将$y替换成2*4,而不是8,然后如果我们打开了Warning的话,会 看到Perl把2*4解释成了2(因为Perl需要一个Number做-1的运算,按照我们前面学的,Perl在做自动类型转换)。千万注意。

@fred = qw(eating rocks is wrong);
$fred = "right";               # we are trying to say "this is right[3]"
print "this is $fred[3]\n";    # prints "wrong" using $fred[3]
print "this is ${fred}[3]\n";  # prints "right" (protected by braces)
print "this is $fred"."[3]\n"; # right again (different string)
print "this is $fred\[3]\n";   # right again (backslash hides it)

还有这里的例子,我们用{}强行显示定义了变量,从而将数组fred和变量fred分开了(Perl中数组和变量的名字是可以一样的,因为他们类型不同,但是我们强烈建议不要这样做,因为这样是在自找麻烦)。  
  
14. foreach Control Structure. foreach可以循环遍历一个List,和shell编程中的循环有点类似。比如:

Code: Select allforeach $rock (qw/ bedrock slate lava /) {
  print "One rock is $rock.\n";  # Prints names of three rocks
}
foreach 中有个非常重要的关键点:就是foreach中的control  variable(上面例子中的$rock),不是List中变量的一个copy,而就是这个变量本身,换言之,在foreach中如果我们修改了 control variable,就会对List中的数据产生修改,千万注意。比如这个例子,就把List中每个元素都加上了\t和\n:
Code: Select all@rocks = qw/ bedrock slate lava /;
foreach $rock (@rocks) {
  $rock = "\t$rock";       # put a tab in front of each element of @rocks
  $rock .= "\n";           # put a newline on the end of each
}
print "The rocks are:\n", @rocks; # Each one is indented, on its own line
15.  此外,foreach的control variable还有一个注意点,就是Perl会在foreach循环开始之前自动将control  variable备份起来,当foreach循环结束后,Perl会自动将control  variable的值恢复成foreach循环前的值,这一点和C都是不一样。换句话说,我们不用担心control  variable的值在循环开始和结束后会有变化,但是如上面14点所描述的一样,在foreach循环体中对control  variable的修改会直接影响List中的相应变量的值。
16. Perl's Favorite Default: $_ 。$_这个变量在Perl中很重要,也很常用,他是Perl中的默认变量--当我们的代码中没有指定变量的时候,$_就成了默认的变量。如:
Code: Select allforeach (1..10) {  # Uses $_ by default
  print "I can count to $_!\n";
}

如上,在foreach中没有指定control variable,那么$_就成了control variable. 又如:

$_ = "Yabba dabba doo\n";
print;  # prints $_ by default

由于print没有指定print什么变量,那么Perl就会打印$_变量的值。

17. reverse Operator.  reverse用来反转一个List,有关reverse只需要记住一点:reverse不会修改List本身,reverse会把翻转后的结果作为返回 值传回,如果我们要修改List本身,那么只需要reverse的返回值再赋给List本身就可以了。

@fred   = 6..10;
@barney = reverse(@fred);  # gets 10, 9, 8, 7, 6
@wilma  = reverse 6..10;   # gets the same thing, without the other array
@fred   = reverse @fred;   # puts the result back into the original array

reverse @fred;         # WRONG - doesn't change @fred
@fred = reverse @fred; # that's better

18. sort Operator.  sort用来将一个List中的东西排序,默认情况下,sort是按照ASCII码表来排序的,那就是--大写字母排在小写字母前面,数字排在字母前面, 标点符号充斥在ASCII码表的各处。在第13章会描述如何自定义sort的排序逻辑。和reverse一样,sort不会修改List本身,sort是 把排序后的结果作为返回值返回,要想修改List本身,要把sort的返回值重新赋给List本身就可以了。

@rocks   = qw/ bedrock slate rubble granite /;
@sorted  = sort(@rocks);        # gets bedrock, granite, rubble, slate
@back    = reverse sort @rocks; # these go from slate to bedrock
@rocks   = sort @rocks;         # puts sorted result back into @rocks
@numbers = sort 97..102;        # gets 100, 101, 102, 97, 98, 99

注意最后一个例子,排序的结果是100排在第一个哦,因为这是按照ASCII码表来排序的。

sort @rocks;          # WRONG, doesn't modify @rocks
@rocks = sort @rocks; # Now the rock collection is in order

19. Scalar and List Context.  书上说本节是本章,甚至是本书最重要的一节,其实本节就是描述在不同的context上,scalar和list类型的变量的不同行为,就好像语言中一个 单词在不同的语境下会有不同意思的含义一样。这里的context指的就是变量所处的一个环境,一个expression。

20. 比如:

42 + something # The something must be a scalar
sort something # The something must be a list

@people = qw( fred barney betty );
@sorted = sort @people; # list context: barney, betty, fred
$number = 42 + @people;  # scalar context: 42 + 3 gives 45

看这个例子,people是一个List,在最后一句代码中,我们将一个scalar变量和people相加,此时@people返回的是这个List中element的数量,而不是表示List本身,这就是同一个变量在不同的context下的不同表现。
一般来说,确定一个变量的真实表现,主要应该先看等号左边的变量类型是什么,这样就确定了等号右边expression应该给出一个什么类型的变量(是Scalar还是List),然后expression中的变量根据这样的要求给出不同的解释方法。这样的例子还有:

@list = @people; # a list of three people
$n = @people;    # the number 3

21. 给出更多的一些例子和规则。比如,在一个List context中用sort,这是正常用法,在一个Scalar  Context中用sort,sort会返回undef;在一个List  context中用reverse,reverse将List的元素全部倒序重新排列,如果在Scalar  Context中用reverse,reverse会返回一个倒序的String:

@backwards = reverse qw/ yabba dabba doo /;   # gives doo, dabba, yabba
$backwards = reverse qw/ yabba dabba doo /;   # gives oodabbadabbay

这里还有更多的例子:

$fred = something;            # scalar context
@pebbles = something;         # list context
($wilma, $betty) = something; # list context
($dino) = something;          # still list context!

注意最后一个例子,最后一个例子等号左边是一个List,不是一个Scalar变量。

22. 再来看例子,这里的例子是把Scalar的变量赋给一个List类型的变量:

@fred = 6 * 7;    # gets the one-element list (42)
@barney = "hello" . ' ' . "world";
@wilma = undef; # OOPS! Gets the one-element list (undef)
# which is not the same as this:
@betty = ( );    # A correct way to empty an array

23. Perl提供一个叫做scalar的关键字,用这个关键字可以手动强制指定一个变量为Scalar类型,如:

@rocks = qw( talc quartz jade obsidian );
print "How many rocks do you have?\n";
print "I have ", @rocks, " rocks!\n";        # WRONG, prints names of rocks
print "I have ", scalar @rocks, " rocks!\n"; # Correct, gives a number

在第三句代码中,print会把rocks这个array中的每个元素都打印出来,而我们想让print打印的是这个array的size,所 以,第四句代码中,我们用scalar关键字提示Perl,这里的@rocks作为Scalar变量来解释,所以就打印这个array的size了。

24. <STDIN> in List Context.  前面我们介绍了用<STDIN>可以读入一行(从文件或者是从keyboard读取),赋给一个Scalar变量;这里介绍 把<STDIN>用在List  Context时候的情景--结果是,<STDIN>会一直读到end-of-file,然后把每行的string都作为List中的一个 element赋过去:

@lines = <STDIN>; # read standard input in list context

lines是一个List,所以,如果此时的<STDIN>是一个FILE的话,会一直读到文件末尾,然后每行作为一个 element赋给这个List;如果<STDIN>是keyboard的话,会把每行输入的string都作为一个element赋给这个 List,直到用户按下了ctrl+D(Linux/UNIX系统下,当然这个组合键可以通过stty命令来重定义,windows系统下一般是按下 ctrl+z表示EOF)。

这样每行读出来的string,末尾是有一个\n的,和前面一样,我们可以用chomp来去掉这个行尾的\n,不过有趣的是,chomp也可以用在List Context, 此时chomp会把List中每个element string行尾的\n去掉,很方便哦!

chomp(@lines = <STDIN>); # Read the lines, not the newlines

不过在使用<STDIN>的这个特性的时候,也要注意一些性能问题,比如一次性读入一个400MB的log  file的时候会如何呢?和以往一样,Perl不会限制这个size的大小,只要memory够用,不过当我们真的干这样事情的时候,大概会用掉1G左右 的内存空间,如果内存不够,那就要小心了,如果内存够,自然就没有问题了。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-156761-1-1.html 上篇帖子: 使用Perl进行网页数据抓取[初学者简明版] 下篇帖子: 【Perl】Path::File 目录的创建和删除
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表