Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2060234
  • 博文数量: 178
  • 博客积分: 2076
  • 博客等级: 大尉
  • 技术积分: 2800
  • 用 户 组: 普通用户
  • 注册时间: 2008-01-10 10:50
文章分类

全部博文(178)

文章存档

2010年(4)

2009年(13)

2008年(161)

我的朋友

分类:

2008-07-30 13:48:21

Perl 语言入门(第四版)
1 / 201 9/21/2006
Perl 语言入门
(第四版)
作者:Brian d foy, Tom Phoenix, Randal L.Schartz
译者: lebk 校对: 鄢元满
Perl 语言入门(第四版)
2 / 201 9/21/2006
目录
前言: .................................................................................................................................................................................................8
第一章概述..............................................................................................................................................................................................9
1.1 问题和解答....................................................................................................................................................................................9
1.1.1 本书适合你吗? .......................................................................................................................................................................................9
1.1.2 为什么如此多的脚注?............................................................................................................................................................................9
1.1.3 练习题和解答呢? .................................................................................................................................................................................10
1.1.4 习题前的数字是什么意思?.................................................................................................................................................................. 10
1.1.5 如果我是Perl 教师,怎么办呢? .........................................................................................................................................................10
1.2 Perl 代表什么? ....................................................................................................................................................................... 11
1.2.1 Larry 为什么发明Perl?......................................................................................................................................................................11
1.2.2 为什么Larry 不采用别的语言?........................................................................................................................................................... 11
1.2.3 Perl 容易学习吗?................................................................................................................................................................................... 12
1.2.4 Perl 为什么如此流行?...........................................................................................................................................................................13
1.2.5 Perl 正在发生怎样的事情?...................................................................................................................................................................13
1.2.6 Perl 擅长什么?....................................................................................................................................................................................... 13
1.2.7 Perl 不擅长什么?................................................................................................................................................................................... 14
1.3 怎样获得Perl? .........................................................................................................................................................................14
1.3.1 什么CPAN?.......................................................................................................................................................................................... 14
1.3.2 怎样获得支持? .....................................................................................................................................................................................15
1.3.3 有其它的支持吗? .................................................................................................................................................................................15
1.3.4 当发现Perl 中有错误时,该怎么办? .................................................................................................................................................16
1.4 怎样才能写一个Perl 程序?.....................................................................................................................................................16
1.4.1 一个简单的例子.....................................................................................................................................................................................17
1.4.2 这个程序有些什么? ............................................................................................................................................................................. 18
1.4.3 怎样编译Perl?....................................................................................................................................................................................... 19
1.5 快速了解Perl .............................................................................................................................................................................19
1.6 第六节练习................................................................................................................................................................................20
第二章标量数据......................................................................................................................................................................................21
2.1 数字............................................................................................................................................................................................. 21
2.1.1 所有数字内部的格式一致.......................................................................................................................................................................21
2.1.2 浮点数..................................................................................................................................................................................................... 21
2.1.3 整数......................................................................................................................................................................................................... 22
2.1.4 非十进制整数.......................................................................................................................................................................................... 22
2.1.5 数字操作符.............................................................................................................................................................................................. 23
2.2 字符串......................................................................................................................................................................................... 23
2.2.1 单引号字符串.......................................................................................................................................................................................... 24
2.2.2 双引号字符串.......................................................................................................................................................................................... 24
2.3.3 字符串操作符.......................................................................................................................................................................................... 25
2.2.4 数字和字符串之间的自动转换............................................................................................................................................................... 26
2.3 Perl 内嵌的警告(warnings)......................................................................................................................................................... 26
Perl 语言入门(第四版)
3 / 201 9/21/2006
2.4 标量变量.....................................................................................................................................................................................27
2.4.1 选择好的变量名......................................................................................................................................................................................28
2.4.2 标量赋值.................................................................................................................................................................................................. 28
2.4.3 二元赋值操作符.....................................................................................................................................................................................29
2.5 print 输出.....................................................................................................................................................................................29
2.5.1 字符串中标量变量的内插.......................................................................................................................................................................30
2.5.2 操作符优先级和结合性...........................................................................................................................................................................31
2.5.3 比较运算符.............................................................................................................................................................................................. 32
2.6 if 控制结构...................................................................................................................................................................................33
2.6.Boolean 值...................................................................................................................................................................................................33
2.7 用户输入.....................................................................................................................................................................................34
2.8 chomp操作...................................................................................................................................................................................35
2.9 while 控制结构.............................................................................................................................................................................35
2.10 undef 值......................................................................................................................................................................................36
2.1.1 defined 函数...........................................................................................................................................................................37
2.1.2 练习.......................................................................................................................................................................................37
第三章列表和数组..................................................................................................................................................................................38
3.1 访问数组元素.............................................................................................................................................................................39
3.2 特殊的数组索引.........................................................................................................................................................................39
3.3 列表..............................................................................................................................................................................................40
3.3.1 qw 简写...................................................................................................................................................................................................41
3.4 列表赋值.....................................................................................................................................................................................42
3.4.1 pop 和push 操作......................................................................................................................................................................................43
3.4.2 shift 和unshift 操作.................................................................................................................................................................................44
3.5 将数组插入字符串...................................................................................................................................................................... 44
3.6 foreach 控制结构.........................................................................................................................................................................45
3.6.1 Perl 最常用的默认变量:$_...................................................................................................................................................................46
3.6.2 reverse 操作.............................................................................................................................................................................................. 46
3.6.3 sort 操作...................................................................................................................................................................................................47
3.7 标量和列表上下文...................................................................................................................................................................... 47
3.7.1 在标量Context 中使用List-Producing 表达式......................................................................................................................................48
3.7.2 在列表Context 中使用Scalar-Producing 表达式...................................................................................................................................50
3.7.3 强制转换为标量Context ........................................................................................................................................................................ 50
3.8在列表Context 中......................................................................................................................................................... 50
3.9 练习............................................................................................................................................................................................. 51
第四章子程序..........................................................................................................................................................................................53
4.1 定义一个子程序.........................................................................................................................................................................53
4.2 调用子程序.................................................................................................................................................................................54
4.3 返回值......................................................................................................................................................................................... 54
4.4 参数(Arguments) .........................................................................................................................................................................56
4.5 子程序中的私有变量.................................................................................................................................................................57
4.6 参数列表的长度.......................................................................................................................................................................... 57
4.6.1 更好的&max 程序..................................................................................................................................................................................58
4.6.2 空参数列表.............................................................................................................................................................................................. 59
Perl 语言入门(第四版)
4 / 201 9/21/2006
4.7my 变量的注释..............................................................................................................................................................................59
4.8 使用strict Pragma .......................................................................................................................................................................60
4.9 返回操作.....................................................................................................................................................................................61
4.9.1 省略符号&.............................................................................................................................................................................................. 62
4.10 非标量返回值...........................................................................................................................................................................63
4.11 练习............................................................................................................................................................................................64
第五章输入与输出..................................................................................................................................................................................65
5.1 从标准输入设备输入.................................................................................................................................................................. 65
5.2 从<>输入.....................................................................................................................................................................................66
5.3 调用参数......................................................................................................................................................................................68
5.4 输出到标准输出设备.................................................................................................................................................................. 69
5.5 使用printf 格式化输出................................................................................................................................................................ 71
5.5.1 数组和printf ................................................................................................................................................................................................. 72
5.6 句柄..............................................................................................................................................................................................73
5.7 文件句柄的打开.......................................................................................................................................................................... 74
5.7.1 Bad 文件句柄........................................................................................................................................................................................... 76
5.7.2 关闭文件句柄.......................................................................................................................................................................................... 76
5.8 严重错误和die ...........................................................................................................................................................................77
5.8.1 警告信息和warn .................................................................................................................................................................................... 78
5.9 使用文件句柄..............................................................................................................................................................................78
5.9.1 改变默认的输出句柄..............................................................................................................................................................................79
5.10 重新打开文件句柄...................................................................................................................................................................79
5.11 练习........................................................................................................................................................................................... 80
第六章哈希........................................................................................................................................................................................... 81
6.1 什么是哈希? ..............................................................................................................................................................................81
6.1.1 为什么使用Hash? ..................................................................................................................................................................................82
6.2 哈希元素的存取.......................................................................................................................................................................... 84
6.2.1 作为整体的hash ......................................................................................................................................................................................85
6.2.2 Hash 赋值................................................................................................................................................................................................86
6.2.3 大箭头符号(=>).................................................................................................................................................................................87
6.3 哈希函数......................................................................................................................................................................................87
6.3.1 keys 和values 函数..................................................................................................................................................................................87
6.3.2 each 函数.................................................................................................................................................................................................. 88
6.4 哈希的通常用法.......................................................................................................................................................................... 89
6.4.1 exists 函数................................................................................................................................................................................................90
6.4.2 delete 函数................................................................................................................................................................................................90
6.4.3 hash 元素的内插......................................................................................................................................................................................90
6.5 练习..............................................................................................................................................................................................91
第七章正则表达式..................................................................................................................................................................................92
7.1 什么是正则表达式? .................................................................................................................................................................. 92
7.2 使用简单的模式.......................................................................................................................................................................... 93
7.2.1 元字符..................................................................................................................................................................................................... 93
7.2.2 简单的量词.............................................................................................................................................................................................94
7.2.3 模式中的分组.......................................................................................................................................................................................... 94
Perl 语言入门(第四版)
5 / 201 9/21/2006
7.2.4 选择符..................................................................................................................................................................................................... 94
7.3 字符类..........................................................................................................................................................................................95
7.3.1 字符类的简写.......................................................................................................................................................................................... 95
7.3.2 简写形式的补集.....................................................................................................................................................................................96
7.4 练习..............................................................................................................................................................................................96
第八章正则表达式的应用...................................................................................................................................................................... 98
8.1 使用m//匹配...............................................................................................................................................................................98
8.2 可选的修饰符..............................................................................................................................................................................98
8.2.1 不区分大小写:/i .................................................................................................................................................................................... 98
8.2.2 匹配任何字符:/s.................................................................................................................................................................................... 99
8.2.3 添加空格:/x........................................................................................................................................................................................... 99
8.2.4 将可选字符结合起来...........................................................................................................................................................................100
8.2.5 其它选项................................................................................................................................................................................................100
8.3 锚定............................................................................................................................................................................................100
8.3.1 词锚定...................................................................................................................................................................................................101
8.4 绑定操作符,=~ .......................................................................................................................................................................101
8.5 模式内的内插...........................................................................................................................................................................102
8.6 匹配变量...................................................................................................................................................................................103
8.6.1 内存值的保存.......................................................................................................................................................................................104
8.6.2 自动匹配变量........................................................................................................................................................................................105
8.7 一般的数量词............................................................................................................................................................................ 106
8.8 优先级........................................................................................................................................................................................106
8.8.1 优先级练习............................................................................................................................................................................................107
8.8.2 更多........................................................................................................................................................................................................107
8.9 模式测试程序...........................................................................................................................................................................107
8.10 练习..........................................................................................................................................................................................108
第九章使用正则表达式处理文件........................................................................................................................................................109
9.1 使用s///进行替换...................................................................................................................................................................... 109
9.1.1 使用/g 进行全局替换............................................................................................................................................................................ 110
9.1.2 不同的分隔符........................................................................................................................................................................................ 110
9.1.3 可选的修饰符....................................................................................................................................................................................... 111
9.1.4 绑定操作............................................................................................................................................................................................... 111
9.1.5 大小写转换............................................................................................................................................................................................ 111
9.2split 操作..................................................................................................................................................................................... 112
9.3join 函数...................................................................................................................................................................................... 113
9.4 列表上下文中的m// ................................................................................................................................................................. 114
9.5 更强大的正则表达式................................................................................................................................................................ 114
9.5.1 非贪婪的数量词.................................................................................................................................................................................... 115
9.5.2 匹配多行文本....................................................................................................................................................................................... 116
9.5.3 更新大量文件........................................................................................................................................................................................ 117
9.5.4 在命令行中进行修改........................................................................................................................................................................... 119
9.5.5 非捕捉用的括号...................................................................................................................................................................................120
9.6 练习............................................................................................................................................................................................121
第十章更多控制结构............................................................................................................................................................................ 122
Perl 语言入门(第四版)
6 / 201 9/21/2006
10.1unless 控制结构........................................................................................................................................................................ 122
10.1.1unless 和else 语句一起使用................................................................................................................................................................122
10.2until控制结构...........................................................................................................................................................................123
10.3 表达式修饰符.......................................................................................................................................................................... 123
10.4The Naked Block 控制结构....................................................................................................................................................... 125
10.5 elsif 语句...................................................................................................................................................................................126
10.6 自增和自减..............................................................................................................................................................................126
10.6.1 自动增量的值......................................................................................................................................................................................127
10.7for 控制结构..............................................................................................................................................................................128
10.7.1foreach 和for 的关系............................................................................................................................................................................130
10.8 循环控制..................................................................................................................................................................................130
10.8.1 last 操作................................................................................................................................................................................................131
10.8.2 next 操作..............................................................................................................................................................................................131
10.8.3 redo 操作..............................................................................................................................................................................................132
10.8.4 标签块..................................................................................................................................................................................................133
10.9 逻辑操作符..............................................................................................................................................................................134
10.9.1 短路操作的值......................................................................................................................................................................................135
10.9.2 三元操作符?: .....................................................................................................................................................................................135
10.9.3 控制结构:使用部分求值的操作符...................................................................................................................................................136
10.10 练习........................................................................................................................................................................................138
第十一章文件检验................................................................................................................................................................................139
11.1 文件检测操作...........................................................................................................................................................................139
11.2 stat 和lstat 函数.......................................................................................................................................................................142
11.3 localtime 函数...........................................................................................................................................................................143
11.4 位操作....................................................................................................................................................................................... 144
11.4.1 使用位串..............................................................................................................................................................................................145
11.5 使用特殊的下划线文件句柄...................................................................................................................................................145
11.6 练习..........................................................................................................................................................................................146
第十二章目录操作................................................................................................................................................................................147
12.1 在目录树上移动...................................................................................................................................................................... 147
12.2 Globbing...................................................................................................................................................................................147
12.3 Globbing 的替换语法..............................................................................................................................................................148
12.4 目录句柄..................................................................................................................................................................................149
12.5 递归的目录列表...................................................................................................................................................................... 151
12.6 操作文件和目录...................................................................................................................................................................... 151
12.7 删除文件..................................................................................................................................................................................151
12.8 重命名文件..............................................................................................................................................................................152
12.9 连接和文件..............................................................................................................................................................................153
12.10 创建和删除目录.................................................................................................................................................................... 157
12.11 修改权限.................................................................................................................................................................................159
12.12 改变所有者............................................................................................................................................................................ 159
12.13 改变时间戳............................................................................................................................................................................ 159
12.14 练习........................................................................................................................................................................................160
第十三章字符串和排序........................................................................................................................................................................ 161
Perl 语言入门(第四版)
7 / 201 9/21/2006
13.1 使用索引寻找子串.................................................................................................................................................................. 161
13.2 使用substr操作子串............................................................................................................................................................... 162
13.3 使用sprintf 格式化数据..........................................................................................................................................................163
13.3.1 在“货币数字”中使用sprintf ...........................................................................................................................................................164
13.4 高级排序..................................................................................................................................................................................165
13.4.1 依据值对Hash 进行排序....................................................................................................................................................................168
13.4.2 对多个keys 排序.................................................................................................................................................................................168
13.5 练习..........................................................................................................................................................................................169
第十四章进程管理................................................................................................................................................................................171
14.1 系统函数..................................................................................................................................................................................171
14.1.1 避免Shell.............................................................................................................................................................................................172
14.2exec 函数...................................................................................................................................................................................174
14.3 环境变量..................................................................................................................................................................................174
14.4 使用反引号捕捉输出..............................................................................................................................................................175
14.4.1 在List context 中使用反引号..............................................................................................................................................................177
14.5 像文件句柄那样处理..............................................................................................................................................................178
14.6 使用fork...................................................................................................................................................................................179
14.7 发送和接收信号...................................................................................................................................................................... 180
14.8 练习..........................................................................................................................................................................................182
第十五章PERL 模块...............................................................................................................................................................................183
15.1 查找模块..................................................................................................................................................................................183
15.2 安装模块..................................................................................................................................................................................183
15.3 使用简单的模块...................................................................................................................................................................... 184
15.3.1. File::Basename 模块........................................................................................................................................................................185
15.3.2.仅使用模块中的一些函数................................................................................................................................................................186
15.3.3.File::Spec 模块..................................................................................................................................................................................187
15.3.4.CGI.pm ..............................................................................................................................................................................................188
15.3.5.数据库和DBI ......................................................................................................................................................................................189
15.4 练习..........................................................................................................................................................................................190
第十六章一些高级的PERL 技术..........................................................................................................................................................191
16.1 利用eval 捕获错误.................................................................................................................................................................. 191
16.2 使用grep 在列表得到元素.....................................................................................................................................................193
16.3 使用map 对列表项进行变换..................................................................................................................................................194
16.4 不用双引号的hash keys ..........................................................................................................................................................195
16.5Slices..........................................................................................................................................................................................195
16.5.1 Array Slice............................................................................................................................................................................................197
16.5.2Hash Slice..............................................................................................................................................................................................198
16.6 练习..........................................................................................................................................................................................200
练习题答案............................................................................................................................................................................................. 201
Perl 语言入门(第四版)
8 / 201 9/21/2006
前言:
感谢我的家人。是你们给与了我一切。无论走到哪里,你们都让我感到温暖和充满勇气。
感谢我的女朋友:红梅。你对我的照顾和给予我的爱,让我的生命变得完整。
感谢我的朋友阿满在百忙之中抽出时间校对。但本书质量应完全由译者负责。
感谢出现在我生命中所有的人。那些和我一起逃学,一起罚站,一起偷邻居甘蔗的伙伴;那些和我一起抽烟,一起喝酒,
一起唱歌侃大山的同学;那些天冷提醒我穿衣,过马路提醒我小心的知己朋友;还有那些和我斗嘴的,和我打架的,是你
们锻炼了我的口才,是你们强壮了我的身体。你们还好吗?
最后我想说:当你很饿,面对美味佳肴,请不要急于动筷子;当你很渴,面对清泉甘露,请不要急于动嘴;当你很冷,面
对暖炕热被,请不要急于动腿。当你所渴望的东西正在你眼前的时候,请放慢你的脚步,用心去感受。
lebk
Perl 语言入门(第四版)
9 / 201 9/21/2006
第一章概述
欢迎使用小骆驼书。
本书是第四版,自93 年以来,有超过50 万的读者喜欢它。至少,我们希望他们喜欢它。不管怎样,我们写此书时非常开
心◆。
◆本书第一版由Randal L.Schwartz 著,第二版由Randal,Tom Christiansen 著,第三版由Randal,Tom Phoenix 著,本版由Randal, Tom Ponenix,
和brian foy 著。因此,在本版中,当说“我们”时,指的是最后三位。现在,你可能猜想,为什么在第一页就说写本书我们非常开心
(过去时态),理由很简单:因为我们是从后往前写的。这听起来很奇怪。但是,坦白讲,当写完索引后,剩下的就变的很容易了。
1.1 问题和解答
你或许对Perl 有些疑问,也可能是针对本书,特别是当你已经大致浏览本书后。因此,我们将用本章来回答这些问题。
1.1.1 本书适合你吗?
如果你和我们类似,那你很可能正站在书架前◆,考虑是否要买这本羊骆驼书来学习Perl 或是买另一本由蛇(有迂回的
含义),饮料,或者一些字母命名的语言◆的书。你站了两分钟,书店经理走过来通知你这不是图书馆◆,你要么买要么
快点离开。可能,你利用这两分钟时间来查看一个Perl 程序,来了解其强大功能以及它能完成怎样的工作。如果是那样
的话,您因该浏览本章剩下的章节。
◆实际上,如果和我们一样,你因该站在图书馆,而不是书店。当然我们有一点吝啬。
◆在你写信告诉我们那是段愉快,而非迂回(伤脑筋)的历程之前,其实我们想的是CORBA。
◆除非它是,否则
1.1.2 为什么如此多的脚注?
感谢你注意到这些。本书中有大量的脚注。忽略它们就行了。我们需要脚注的原因是Perl 中有大量的异常。这是好事情,
因为生活本身就充满了意外。
但这并不意味着我们不能老实的写:“The fizzbin operator frobnicates the hoozistatic variables”◆,而不写任何脚注来描述
异常情况。事实上,我们相当老实,所以我们写了脚注。但你可以老老实实的忽略它们。(这种解决办法听起来相当有趣)。
许多异常和移植性相关。Perl 最早在Unix 系统中使用,因此它和Unix 渊源极深。但只要有可能,我们就演示它非预期的
Perl 语言入门(第四版)
10 / 201 9/21/2006
行为,无论这种结果是由non-Unix 系统,还是别的原因引起的。我们希望那些对Unix 一无所知的读者也认为本书是一本
好的Perl 教程。(同时,也能附带学些Unix 的知识)。
其余的大量的异常都和“80/20”规则相关。我们是指80% 的Perl 可用20%的篇幅介绍。剩下的20%需要80%篇幅。为了
保持本书的大小,我们将在正文中介绍最常用的,最容易讲明白的内容,在脚注中介绍别的(它们字体更小,因此可以在
相同的空间内写入给多的内容)◆但你学习本书时,如果没有阅读脚注,很可能在后面的章节中需要回过头来查看。如果
是那样,或者在学习的过程中,出于好奇,那就读读这些脚注吧。尽管大多数脚注只是一些计算机的笑话。
我们甚至讨论为了节省纸张,把整本书用脚注组成,但脚注跟着脚注看起来有些疯狂。
1.1.3 练习题和解答呢?
练习题在每章的末尾。由于我们三人向几千人介绍相同的材料◆。因此我们仔细的选择了这些习题,让你更有机会犯错。
◆不是同时的
并不是我们希望你犯错,而是你需要这种经验。因为在Perl 生涯中,这些是你最可能犯的错误,因此我们现在就应当提
醒你。那些在阅读本书时犯的错误,可能不会在项目的终止日期时重犯。当你出错是我们会帮助你找到错误的原因;附录
A 有每一个习题的解答,和小段注释。当完成习题时请检查答案。
不要在仔细尝试之前看答案。自己解决比读解答学的更牢靠。如果没有找到答案,也不要太伤心。继续阅读下一章。
如果你完全没有犯错误,也因当在完成时看下答案。解答的注释中可能有关于这段程序的一些不明显地方的介绍。
1.1.4 习题前的数字是什么意思?
每一习题前都有一个由中括号括起来的数字,像下面这样:
[2]习题前面方括号中的数字2 是什么含义?
这个数字是我们关于你大概要花多长时间来解决这道题的(非常粗略的)估计。由于非常粗略,当你在一半或两倍的时间
内完成(书写,调试,测试)时,也不必太惊讶。另外,当被题目难住时,我们也不会告诉任何人你偷看了附录A。
1.1.5 如果我是Perl 教师,怎么办呢?
如果你是Perl 的教师,决定采用本书作为教科书(过去的年月里,许多人采用了它),你因当知道我们尽力使每一组联系
能让大多数学生在45 分钟~1 小时内完成,其间有些休息时间。一些练习可能很快就完成了,另一些也许花的时间要长
些。那是因为,当我们写下了方括号中的数字时,我们发现不知道怎么把它们加起来。(幸运的是,我们知道怎样用计算
机来做到)。
Perl 语言入门(第四版)
11 / 201 9/21/2006
1.2 Perl 代表什么?
Perl 一般被称为“实用报表提取语言”(Practical Extraction and Report Language),虽然有时被称做“病态折中垃圾列表器”
(Pathologically Eclectic Rubbish Lister)。它是术语,而不仅仅是简写,Perl 的创造者,Larry Wall 提出第一个,但很快又扩
展到第二个。那就是为什么“Perl”没有所有字母都大写。没必要争论那一个正确,Larry 两个都认可。
你也可能看到“perl”,所有的字母都是小写的。一般,“Perl”,有大写的P,是指语言本身,而“perl”,小写的p,是指
程序运行的解释器。
1.2.1 Larry 为什么发明Perl?
Larry 在80 年代中期发明了Perl 语言,当时他想从像新闻组邮件那样的文件中产生一些有用的报表给一个bug 报告系统,
awk 语言不能胜任这任务。Larry,作为一个懒惰的程序员◆,为了彻底的解决这个问题,决定发明一种一般用途的工具,
至少还能在一个不同的地方使用。这次努力的结果就是Perl V0。
◆我们不是无理的说Larry 很懒惰;实际上懒惰是一种美德。手推车是由那些懒于搬东西的人发明的;文字是由那么懒于记忆的人发明
的。Perl 是由那些不创造一种新的语言就懒于完成任务的人发明的。
1.2.2 为什么Larry 不采用别的语言?
程序语言本身没有缺陷,有吗?但是,在Larry 那个时候,他没有找到满足需要的语言。如果现在的某种语言在那个时代
就已产生,很可能Larry 就会采用它。他需要能像shell 或awk 那样快速编码,同时具有如grep, cut, sort, sed◆等这些高级
工具的强大功能,但又不采用像C 那样的语言。
◆如果不知道它们,不用担心。这些是Larry 的Unix 工具盒中的程序。但它们还不能解决手头的工作。
Perl 填补了低级语言(如C,C++,汇编语言)和高级语言(如shell 编程)的空白。低级语言通常难于编码,并且丑陋,
但速度快,且无限制;高级语言,在速度上,很难超过书写良好的低级语言。在低级语言里,你几乎能完成任何事。高级
语言,正好相反,一般速度慢,困难,丑陋,有限制;如果没有系统提供的函数,shell,批处理语言能完成的工作相当有
限。Perl 简单,几乎是无限制的,速度快,也有些丑陋。
让我们从另一个角度来看关于Perl 的这四点:
第一,Perl 简单。如你将要见到的,这意味着容易使用。但不是特别容易学习。如果学习开车,你花数周或数月学习,然
后就很容易的开车了。当你花了许多时间来学习Perl 时,Perl 对你来说就简单了◆。
◆当然,我们并不希望你翻车()。
Perl 几乎没有限制。几乎没有什么事不能由Perl 来完成。你一般不希望用Perl 来书写内核级的中断驱动程序(虽然Perl
能完成)。但针对一般工作中遇到的问题,从一次性程序到工业级的运用,Perl 都能出色的完成。
Perl 语言入门(第四版)
12 / 201 9/21/2006
Perl 速度快。那是由于,所有的Perl 开发者都使用Perl,他们希望它快。如果某人想加一个很酷的功能到Perl 中,但它会
降低其它程序的速度,Larry 基本上会拒绝添加它除非找到一个方法使它足够快。
Perl 有些丑。这是事实。O 'Reilly 给Perl 的图标是骆驼,这种动物是著名的骆驼书(也被称为Perl 语言编程)的封面,还
有它的兄弟-本书(它的姐妹,羊驼书(Alpaca))。骆驼有些丑。但是它们努力工作,即便在艰苦的环境中。无论什么困
难骆驼都能完成任务,虽然他们不好看,不好闻,有时还向你吐唾沫。Perl 有些像它。
1.2.3 Perl 容易学习吗?
Perl 容易使用,但有些难学。当然,这具有普适性。设计Perl 时,Larry 做了学多权衡。当遇到能让程序员更容易使用,但
对于初学者难于学习时,Larry 通常倾向于前一种。那是因为,你只学习一次,而将重复使用◆。Perl 有学多做法来节约程
序员的时间。例如学多函数都有默认值;通常,这些默认行为就是你需要的。因此,你将节约学多时间来写像下面这样的
代码◆:
◆如果你每周或每月只花几分钟来使用某种语言。你可能选择那些容易学习的语言,因为在下次使用之前你不需要记住它们。Perl 是给那
些每天至少花20 分钟来写程序的人。
◆我们将不详细解释。本例是将文件中某种格式的数据,换成另一种。所有功能都能在本书中均有找到答案。
while(<>){
chomp;
print join(“\n”,(split /:/))[0,2,1,5]),”\n”;
}
如果不利用Perl 的默认值和简写,本段代码大约会长10~12 倍,这将花更多时间来阅读和书写。并且由于有更多的变量,
将难于维护和调试。如果你懂一点Perl,没有看见代码中的变量,那只是部分问题。它们都使用的默认值。为了减轻程序
员的负担,不得不增加学习的代价,因此你因当学习这些默认值和简写。
一个很好的类比,是英语中的单词。例如,“will not”和“won’t”含义相同。但大多数人说“won’t”而非“will not”,因为这
将节约时间,并且每个人都知道它们有相同含义。同样的,Perl 也把一些常用的语句以一种更简略的形式来表达,就像语
言那样更快的“说”出来,并且被同行所理解。
一旦熟悉了Perl,将发现比shell 引用(或C 声明)花更少的时间,你将有更多的时间在网上冲浪,因为Perl 的强大能力。
Perl 设计成能让你仅用数行就能漂亮的解决问题。你可以把这些工具带到下一份工作中,因为Perl 具有很高的移植性,因
此你将有更多的时间冲浪。
Perl 是高级语言。这意味着,代码很紧凑,通常Perl 程序大约是它对应的的C 程序的1/4 到3/4 长。这使得Perl 程序的读,
写,调试,维护速度都更快。当整个程序在一屏中,不需要向上向下滚动查看时,编程将更容易。并且,由于程序中bugs
的数量大致和它的长度成正比◆(而非和程序的函数),这就意味着,平均起来,短一些的Perl 程序意味着更少的bugs。
◆当程序超过一屏时,bugs 数量会突增。
Perl 语言入门(第四版)
13 / 201 9/21/2006
1.2.4 Perl 为什么如此流行?
Larry 使用了Perl 一段时间,做了些修补后,把它发给新闻组上的用户了,通常被称为“网上”。成千上万的用户问他,做
这个那个以及别的许多问题的方法,Larry 从没有预想过他的小Perl 能处理那些问题。
结果,Perl 持续增长。它的特性越来越多。其移植性越来越强。曾经的一门小语言成长为拥有上千页在线文档,数十本书,
几个主流新闻组(还有大量非主流新闻组),每一天几乎每个当代系统上都有无数的读者和实现者。当然,不要忘了这本小
骆驼书。
1.2.5 Perl 正在发生怎样的事情?
Larry 最近已经不写代码了,但他仍然领导着Perl 的发展,并作出关键决定。Perl 主要由一群勤劳的被称做Perl 5 守门人(Perl
5 Porters)维护。你可以在 中查看他们的工作进展和讨论。
当我们写做此书时(2005 年3 月),Perl 已经发生了许多变化。在过去的几年中,许多人都忙于下一个主要版本:Perl 6。
不要把你的Perl 5 扔到一旁,因为它仍是当前最新和最稳定的版本。我们并不期望Perl 6 的稳定版本会很快出现。当Perl 6
出现时,Perl 5 也不会消失,几年之内,许多人将同时使用这两个版本。Perl 5 的维护者经常把Perl 6 中的好点子加到了Perl
5 中。
2000 年,LarryWall 第一次提出了下一个主要版本是Perl 社区对Perl 的重写。自那以后,一个新的解释器“Parrot”就进入人
们的视野,但并没影响到普通用户。今年(2005 年),唐宗汉(Autrijus Tang)开始利用Haskell 实现作为轻量级的Perl 6
的Pugs(Perl User Golfing System)。来自全球的Perl 和Haskell 开发者提供了帮助。在http://dev.perl.org/perl6
中可以了解到更多信息。
1.2.6 Perl 擅长什么?
Perl 擅长写那些需要在短时间内完成的程序。对于那些需要数十个程序员,花费数年的程序,Perl 也能很好的胜任。当然,
更多的情况是你将写那些从开始构思到实际测试代码只需几十分钟的程序。
Perl 被设计为:90%处理文本,10%针对其它情况。这种能力基本上能满足当今的编程任务。在理想情况下,每一个程序员
懂得每一种语言;对于不同的项目将采用最合适的语言。大多数情况,你要选择Perl◆。当Larry 发明Perl 的时候,Tim
Berners-Lee 还没有web 的丝毫想法,但它们是互联上的完美联姻。许多人声称90 年代初Perl 的发展使得内容能快速转换
为HTML 格式在网上传输,而没有内容Web 是不存在的。当然,Perl 是一种优秀的书写CGI 脚本(由web 服务器运行的
程序)的语言,因此许多人如今仍说:“CGI 仅是Perl 吗?”或者“为什么不说Perl 而说CGI?”,这些论述很有意思。
◆不要较真。如果想知道Perl 是否比X 语言好,那同时学习它们,看那种语言用的最多。这对你是最好的方法。并且,同时学习两种语言,
你将更好的理解它们。花这些时间是值得的。
Perl 语言入门(第四版)
14 / 201 9/21/2006
1.2.7 Perl 不擅长什么?
Perl 擅长许多事,那么什么是它不擅长的呢?不应当使用Perl 来产生二进制码。那些程序可以给别人,或卖给别人,而他
们不能看到程序内部的秘密,同时也不能维护和调试代码。当把Perl 程序给别人时,通常给他们的是源代码而非二进制程
序。
当想要二进制程序时,我们没告诉你不可能。如果人们能安装和运行你的程序,它们也能反编译出来,无论是哪种语言。
当然,这可能和你最初的源代码不同,但它们在某种程度上类似。要保护你的程序,最好的方法是,找些律师,写一份license:
“你可以利用代码做这个,不能做那个。如果违反这个规则,那我们将有律师找你的麻烦,保证让你后悔”。
1.3 怎样获得Perl?
你可能已经有了。至少,我们去的地方都装有它。它被移植到许多系统中,系统管理员通常把它安装在每一台机器上。即
便如此,如果系统上还没有安装,你也可以免费获得。
Perl 通过两种许可证(license)发布。对于大多数Perl 用户而言,任意许可证都足够了。如果想修改Perl,那你因当仔细的
阅读这些许可证,这里面有对修改代码的一些小的限制。对于不修改Perl 的用户来讲,“它是完全免费的。”
因此,它是免费的,可以在任何具有C 编译器的机器上运行。下载它,输入几个命令,它就能自动配置和安装。甚至,你
可以让系统管理员帮你完成这些事◆。除了Unix 和类Unix 系统之外,人们特别喜欢将它移植到其他系统中,例如
Macintosh◆,VMS, OS/2, MS/DOS,Windows,当你阅读本书时,它可能已经被移植到更多的系统中了◆。在这些新系统中
安装Perl,一般要比在Unix 中安装容易。请查看“CPAN”中“移植”这一部分以了解更多信息。
如果系统管理员不能安装Perl,那雇用他有什么用呢?如果你说服他们有困难,去买份pizza,没有几人能对一份免费的pizza 说不。
◆Mac 操作系统中使用的是MacPerl。如果你有Mac 操作系统,它是类Unix 系统,那么你拥有主流的Perl。
◆现在还不适合掌上机,因为它太大了。曾有谣言说它能在WinCE 上运行。
1.3.1 什么CPAN?
CPAN 是全面Perl 归档网络(Comprehensive PerlArchive Network)的缩写,那是一个值得常去的地方。这里有Perl 源码,
容易安装到非类Unix 系统的Perl◆,例子,文档,Perl 扩展部分,Perl 归档信息等。简言之,CPAN 是全面的。
◆一般在Unix 系统中,最好是自己编译Perl。在别的没有C 编译器或其它工具的系统中,CPAN 上提高了二进制的Perl。
CPAN 在全世界有上百个镜像站点。在 和 上可以找到他们。如
果不能上网,你可以从CD-ROM 或DVD-ROM上得到CPAN 中的部分内容。去附近的技术书店,找一份最近的CPAN 归
档光盘,因为CPAN 每天都在更新。2 年以前的文档已经是古董了。最好找一个能上网的朋友,让它帮你烧录份最新的CPAN
文档。
Perl 语言入门(第四版)
15 / 201 9/21/2006
1.3.2 怎样获得支持?
你有所有的源码,所以得自己修复错误(bugs)。
听起来不太好,是吧?但是好事情。由于没有对Perl 源码的限制,任何人都可以修改源码来解决bugs。事实上,当你发现
并确认一个bug 时,也许已经有人解决它了。全世界有几千人在维护Perl。
我们并不是说Perl 有许多bugs,但它是程序,每一个程序都至少有一个bug。为了说明为什么拥有源码会如此有用,想象
你有另一种由一个强大组织,其拥有者是一个光头的亿万富翁所提供的名为Forehead 的语言,(这仅是一个假设。事实上,
我们知道没有一种语言叫做Forehead)。现在想想当你发现Forehead 中有bug 时,你能做什么。首先,你报告它。其次,
你期待他们解决它,希望他们尽快解决它,并且下一版要价不要太高。在下一版中,当增加新功能后,不要引入新的bugs,
希望那个公司不会违反反托拉斯法而导致破产。
对于Perl,你有源码。如果不幸找到的bug 没人解决,这基本上是不可能的,你可以雇佣一个和十个程序员来解决它。同
理,如果买了一台新机器,Perl 不能在上面运行,你可以自己移植它。现在,当你需要一个不存在的功能时,你知道该怎
么做了。
1.3.3 有其它的支持吗?
当然。我们最喜欢的是Perl Mongers。这是由全球的Perl 用户组组成的。在 可以找到更多的信息。可能
你附近的用户组中就有一个专家,或者有人认识某个专家。如果没有这样的组,你可以创建一个。
当然,为了获得帮助,首先,不应该忽略文档。除了用户手册外◆,也可以从CPAN : 上找到合适的
文档,当然还有其它站点,如,上面有Perl 文档的HTML 和PDF 版本, 可以让
你搜寻不同版本的文档, 上有最新版本perlfaq.
◆用户手册s 是类UNIX 系统上的一种文档,如果没有Unix 系统,Perl 有一份针对你的文件系统的文档。
另一份权威的资料是O’Reilly 出版的Perl 编程语言(Programming Perl),通常被称做“骆驼书”,因为封面上有骆驼。(本
书被成为“小骆驼书”)。骆驼书中有详尽的参考信息,一些教程,和大量的关于Perl 的额外信息。还有一本由Johan Vromans
(O’Reilly)编写的Perl 5 的袖珍书,你可以随时把它带在身边(或放在口袋里)。
如果想问问题,网上有大量的新闻组和邮件列表◆。每一天的任意时刻,都有某个时区的Perl 专家在新闻组中回答问题;
在Perl 帝国里太阳永远都不西沉的。这意味着,你问一个问题,通常数几分钟内就有答案。如果不先查看FAQ,很快就有
人热情的帮助你。
◆许多邮件列表可以在 中得到。
官方的Perl 新闻组在comp.lan.perl.*的某些层级上. 当写作本书时,有五个,当它们经常改变。你(或者某个别的负责你们
那里Perl 的人)应当订阅comp.lang.perl.anounce,上面有Perl 的重要通知,特别是关于安全方面的通知。如果需要如何
使用新闻组的帮助,请教附近的专家。
Perl 语言入门(第四版)
16 / 201 9/21/2006
有几个著名的讨论Perl 的Web 站点。其中最著名的是:Perl Monastery (),其中有许多Perl 书籍的作
者和专栏作家,至少包括本书的两位作者。你可以查看 和它相关的邮件列表.
如果需要付费的帮助,有一些公司乐意为你提供任意数量的收费服务的帮助。当然也有许多免费的服务。
1.3.4 当发现Perl 中有错误时,该怎么办?
当发现bug 时,第一件事是再次◆检查文档◆。Perl 有许多特殊性质,和不符规则的地方,你应当确认你发现的是某个特
殊性质还是bug。检查你的Perl 是否是老版本;也许你发现的问题在新一些的版本中已经得到了解决。
◆甚至Larry 也承认,他经常参考这些文档。
◆甚至两次或三次。大多数时候,当我们查看文档以得到找到某一异常行为的解释是,通常得到某些别的细微差别的介绍。
当几乎认定发现的是一个真正的bug 时,问问你周围的人。问问那些工作的,或者附近的Perl 协会中的人。通常,你发现
的仍是一个特殊性质而非bug。
当你肯定发现的是bug,那么准备一个测试案例(test case)。(你以前没有做过吗?)理想的测试案例是,一段小的的程序,
任何Perl 用户都能执行它,并且能得到和你一致的结果。准备好一个能反映这个bug 的测试案例后,应当用perlbug(Perl
中带有它)这个工具来报告它。它会把这个问题用邮件发给Perl的开发者,因此在准备好测试案例之前不要随便使用perlbug。
当把bug 报告出去后,你的事情就完成了,通常能在几分钟内得到回应。一般,你会得到一块小的补丁,然后你的Perl 就
能恢复正常。当然,你也可能得不到任何回答,因为Perl 的开发者没有义务来阅读这些bug 报告。但我们都热爱Perl,我
们不希望Perl 中有任何错误从我们的眼皮底下溜走。
1.4 怎样才能写一个Perl 程序?
是时候问这个问题了(也许你还没有呢)。Perl 程序是文本类型的;可以用你最喜欢的文本编辑器来创建它们(你并不需要
任何特别的开发环境,虽然有一些商业公司提供。我们对于这些工具都使用不多,所以不够资格推荐它们。)
应当使用程序员的文本编辑器(programmer’s text editor),而不是普通的编辑器。它们有什么不同点呢?一般,程序员的编
辑器能提供一个程序员所需要的功能,例如缩进,或非缩进一块代码,能匹配对应的花括号等。在Unix 系统中两个最流行
的程序员编辑器是emacs 和vi(以及它们的克隆和变种)。BBEdit 和Alpha 是Mac 系统中两个优秀的编辑器。在Windows
平台上,口碑很好的编辑器是UltraEdit 和PFE(程序员喜欢的编辑器(Programmer’s Favorite Editor,))。Perlfaq2 上列有几个
其它的编辑器。询问你当地的专家,让他推荐你机器上的编辑器。
对于本书的练习题而言,其代码长度都在20 或30 行之内,任意编辑器都能胜任。
少数的初学者使用字处理软件而非文本编辑器。我们不同意这样做,因为它们不仅不方便,同时很可能带来错误。但我们
不阻止你。当你这样做,在保存时,请把文件保存为仅文本类型的(text only),字处理软件有它自己的格式,这些东西通常
是无用的。许多字处理软件很可能提醒你Perl 程序拼写错误,应当使用更少的分号等等。
Perl 语言入门(第四版)
17 / 201 9/21/2006
某些情况下,你可能在一台机器上书写程序,然后在另一台机器上运行。如果需要这样做,确定传输文件时选的是“文本”
(text)模式或“ASCII”模式而非“二进制”(binary)模式。选择这种方法的原因是,不同机器有不同的文本格式。如果不
这样做,可能得到不一致的结果。某些版本的Perl,当检测到行结束符不对时,会中断执行。
1.4.1 一个简单的例子
依据传统,关于计算机语言的书籍,应当以“Hello,world”这个程序开始。下面是其Perl 版本:
#! /usr/bin/perl
print “Hello,word!\n”;
我们假设你已经把它输入到文本编辑器中。(别担心这个程序的含义以及它如何执行。你将很快知道)。可以将它以你喜欢
的任何名字命名。Perl 不需要任何特别的文件名字或后缀名,但最好不要使用后缀名◆。有些系统中需要像.plx(PerL
eXecutable,可执行的Perl)这样的后缀;可以查看系统上的release notes 来获得这些信息。
◆为什么最好不要后缀呢?想象写了个给保龄球记分的程序,你告诉所有的饿朋友它被称为bowling.plx。某一天,你决定用C 重新写它。
你应该仍以相同的名字命名,表示它仍用Perl 写成?还是告诉他们,它有了个新名字?(噢,请不要把它叫做bowling.c)。事实上,他
们不关心你用什么语言写它,他们只管用。因此,如果当初把它命名为bowling,你将少许多麻烦事。
也许需要做些事情,让你的系统知道它是可执行程序。需要做什么呢,视你的系统而定。也许你只需把它放在某个特定的
路径就行了。(通常你的当前目录就行了)。在Unix 系统中,你需要用chmod 命令将程序变成可执行的,可能像下面:
$ chmod a+x my_program
行首的美圆符号($)(和空格)是shell 提示符,可能你的系统上有些不同。也可在chmod 后使用755 来代替a+x 。两种
方法都是告诉系统这个文件是一个程序(可执行的)。
现在你可以如下运行它:
$ ./my_program
命令开始的点和斜线表示在当前路径查找程序。事实上并非在所有情况下都需要,在完全理解它之前,你应当每次都使用
它◆。如果运行顺利,这看起来像奇迹。通常,你会发现程序有错误。编辑,再试一次,当然不需要每次都使用chmod 命
令,因为这个文件的权限已经被修改过了。(当然,如果没有正确的使用chomd 命令,你可能在shell 中得到不允许操作
“permission denied”这样的信息)。
◆简言之,它防止你运行另一个相同名字的程序(shell 内嵌的)。新手的一个普遍错误是把它命名为test,而许多系统都有这样的程序(shell
内嵌的)。这就是新手运行的为什么不是他们自己程序的原因。
Perl 语言入门(第四版)
18 / 201 9/21/2006
1.4.2 这个程序有些什么?
同任意自由格式语言一样,Perl 通常允许使用任意数量的空白(如空格,制表符,换行符)来使程序易于阅读。但大多数Perl
程序使用一种标准格式,非常像刚才展示的程序。我们强烈的鼓励你使用缩进格式的程序,使你的程序更易阅读;一个好
的文本编辑器能代你完成许多事情。好的注释能让程序易于理解。在Perl 中,注释由#开始,直到本行结束(Perl 中没有“块
注释”(block comments))◆。在本书的程序中我们没有使用大量的注释,因为正文中已经解释了它们,而你自己的程序,
应当使用注释。
◆但是有许多伪造的方法。查看FAQ(在许多情况下,可以用perldoc perlfaq 来查看)
因此,另一种(看起来,有些奇怪)写“Hello,world”的方法是:
#! /usr/bin/perl
print #这是注释
“Hello, world!\n”
; #不要这样写代码
第一行是特殊的注释。在Unix 系统中◆,如果文本的第一行前两个字符是“#!”,接着的就是执行下面文件的程序。在本例
中,这个程序是/usr/bin/perl。
#!行和程序的可移植性相关,需要找到每台机器的存放地点。幸运的是,通常都被放在/usr/bin/perl 或/usr/local/bin/perl 中。
如果不是这样,则需要找到你自己机器上perl 的存放地点,然后使用那个路径。在Unix 系统中,可能使用如下一行找到
perl:
#! /usr/bin/env perl
如果Perl 存放的路径不在你的搜索路径上,应当询问你的系统管理员或者某一个和你使用同一台机器的人。
在非Unix 系统中,传统上把第一行写做#!perl。至少,它立刻告诉程序的维护者,这是一个Perl 程序。如果#!行错了,通
常会在shell 中得到一些错误信息。通常是一些意想不到的信息,如文件不存在“file not found”。这不是说没有找到你的文
件;而是说perl 没有在/usr/bin/perl 那里(其恰当的地方)。我们应当时这条消息更清晰,但它不是Perl 而是shell 给的。(顺
便提醒下,不要把usr 写成user,因为发明Unix 的伙计懒于书写,因此省略了许多字符)。
另一个问题是,你的系统可能根本不支持#!。如果这样,你的shell(或者别的),可能要自己执行你程序,得到一些让人吃
惊的结果。如果不知道这些错误信息,你可以查看perldiag 的用户手册。
“main”程序包含了所有Perl 语句(不包括子程序,你在后面会看到)。和C 或Java 不一样,Perl 中没有“main”程序。
和其它语言不同,Perl 中不需要声明变量。如果其它语言中你必须申明变量,这可能让你惊奇。但它让我们快速写出Perl
程序。如果程序只有两行,不希望其中一行仅仅是申明变量。如果你想声明变量,这是好事;第四章有详细说明。
许多语句,由表达式后接分号组成。下面是你已经看了几次的语句:
Perl 语言入门(第四版)
19 / 201 9/21/2006
print “Hello,world!\n”;
你可能猜想,这行将打印出Hello,world!。结尾是\n,如果使用过C,C++,Java,你可能知道它是换行。当打印出这条信
息后,换行,shell 提示符出现在新行上,而不是在上一条信息之后。单行的输出应当以换行符结束。下一章我们将学习更
多的关于换行符,和其它由反斜线(\)转义的符号。
1.4.3 怎样编译Perl?
只需要运行你的Perl 程序。Perl 的解释器将编译和运行你的程序。
$ perl my_grogram
当运行程序时,Perl 的内部编译器首先遍历整个源程序,把它转变为内部的字节码,它是程序的一种内部数据结构。Perl
的字节码引擎将运行这些字节码。如果200 行有一个语法错误,在执行程序的第二行◆,你将得到出错信息。如果某个循
环运行5000 次,它将一次编译;循环将以最快的速度运行。程序的注释不会增加程序的运行开支。如果某个表达式的计算
结果是一个常数,那在程序开始运行时,就会以这个常数来替换,而不需每次循环重新计算。
一个可能的例外情形是,当写了一个CGI 脚本,它可能每分钟被调用成百上千次。(这个使用率很高。如果一天被调用百
次,千次,我们并不担心)。许多此类程序都只有很短的运行时间,因此重新调入他们将是笔可观的开支。如果这对你是个
严重的问题,你希望找一种方法能让你的程序保持在内存之中。有一个关于Apache web server ( )的模
块:CGI::Fast 兴许能帮助你。
可以保存这些编译过后的字节码以减轻编译的负担吗?或者,更好的是,可以把这些字节码转换为别的语言,如C,然后
编译他们?这两件事,在某种程度上都是可行的,但它们可能使程序难于使用,维护,调试和安装,也可能让你的程序运
行更慢。Perl 6 在这方面有重大改进,但现在讨论还为时过早(当我们写做此书时)。
1.5 快速了解Perl
想看一个有些意思的Perl 程序吗(如果不想,那随便看看)? 如下就是一个:
#! /usr/bin/perl
@lines= `perldoc –u –f atan2`;
foreach(@lines){
s/\w<([^>]+)/\U$1/g;
print;
}
当第一次看见这样的Perl 代码时,你可能觉得很奇怪。(事实上,每次你看到这样的Perl 代码时,都觉得它们奇怪)。让我
们一行一行的来学习它,看看这个例子完成了什么样的任务。(这些解释很简洁;这里只是大致的讲解。在本书的剩下章节,
我们将更加详细的讨论它们。现在并不假定你完全理解它,那是以后的事情。)
第一行是#!这一行,我们已经见过了。你也许要修改它,我们已经讨论过了。
第二行运行了一个外部命令,由` `括起来了。(反引号` 通常在美式键盘数字1 的左边。不要和单引号‘混淆了。)我们用
Perl 语言入门(第四版)
20 / 201 9/21/2006
的命令的是perldoc –u –f atan2;在命令行输入这个命令,看看能得到什么结果。perldoc 这个命令能在大多数机器中使用,
它显示相关的文档◆。这个命令告诉你一些关于反正切函数atan2 的信息;在这里我们把它做为一个外部命令,并处理它
的输出信息。
◆如果perldoc 不能使用。那可能是因为你的系统没有命令行接口,你的Perl 不能通过反引号或piped-open(请查看chapter14)来运行命
令(如perldoc)。如果是这样的,应当跳过需要利用perldoc 的练习。
反引号内的命令的输出被保存在@lines 中。下一行是一个循环,它依行处理@lines 中的信息。循环内语句是缩进的。虽然
Perl 并不需要这样,当这是好的编程习惯。
循环内的第一行让人惊慌;它是s/\w<([^>]+)>/\U$1\g;这里不过多的讨论细节,我们只提示下,它能改变有特殊标记(<>)
的行,在每一perldoc 这个命令的输出中,都至少有一行具有这样的形式。
下一行,令人惊奇的是,它输出每一行(可能是修改过的)。输出的结果和perldoc –u –f atan2 类似,但标记(<>)内的内
容有些不同。
总结下,通过这几行程序,我们运行了另一个程序,把它的输出保存在内存中,修改内存中的数据,再把结果输出来。这
种把数据从一种形式转换成另一种形式的程序在Perl 中很常见。
1.6 第六节练习
通常,每一章都会由一些练习来结束,答案在附录A 中。但是不需要完成这些练习来结束本章的学习,它们只是正文的补
充。
如果不能在机器上练习这些习题,询问你附近的专家。记住应当仔细的推敲这些习题。
1. [7]输入“Hello,world”这个程序,让它运行起来。(你可以任意命名,但像ex1_1 这样的名字就显得好些,它表示第一章
第一个练习。)
2. [5]在命令行输入perldoc –u –f atan2 这个命令,注意它的输出。如果命令无效,询问你的管理员或者从文档(这个版
本的Perl 文档)中查看调用perldoc 或其等价的方法。(你需要做这些来完成下一个练习)
3. [6]运行第二个例子(前一节中),观察它的输出。(提示:注意正确输入这些标点符号)。注意到和第二题输出的不同
地方了吗?
Perl 语言入门(第四版)
21 / 201 9/21/2006
第二章标量数据
在英语以及许多其它的语言中,需要区别单数和复数。作为一门由语言学家发明的语言,Perl 也是类似的。同一般情况一
样,Perl 也有数据类型—标量◆。标量是Perl 中最简单的数据类型。大多数的标量是数字(如255 或3.25e20)或者字符串
(如hello◆或者盖茨堡地址)。你也许把数字和字符串看作不同的事物,但Perl 几乎以相同的观点来看待它们。
◆这个概念和数学或者物理学中的标量(一个单独的是事物)没有多少关系;Perl 中也没有向量。
◆如果使用过别的编程语言,你可能把hello 看作5 个字符的组合,而不是一个单独的东西。但在Perl 中,一个字符串是一个标量数据。
当然,可以使用这个字符串内部的值,你将在后面章节中了解到怎么做。
标量数据可有操作符(如相加和串联),通常会产生一个新的标量数据。标量数据的值可以存放在标量变量中。标量可以从
文件或设备读取,也可以写进去。
2.1 数字
虽然标量在大多数情况下不是数字就是字符串,现在我们最好还是将它们分开来看待。我们首先讨论数字,再讨论字符串。
2.1.1 所有数字内部的格式一致
在下面几段中,你将看到整数(如255,2001 等)和浮点数(有小数点的实数,如3.14159,1.35x1025),但在内部,Perl 都把
它们当作双精度浮点数来处理◆。这就是说在Perl 内部没有整数值。程序中的整数被当做等价的浮点数来处理◆。你也许
注意不到这种转换(或者不关心),但你不应当寻找只属于整数的操作符(不能被浮点数使用的),因为它们不存在◆。
◆双精度浮点类型类似于C 中由double 定义的类型。它们的大小可能和具体的机器相关,许多当代的系统都使用IEEE-754 的格式,它有15
位精度,其范围至少在1e-100 到1e100 之间。
◆有时,Perl 也会使用内部的整数,其对程序员不可见。这样做导致的唯一不同是,程序将运行更快。谁又能抱怨它呢?
◆Perl 中有integer pragma.但如何使用它超出了本书的范围。正如你将看到的,某些操作可以从浮点数得到整数。但那不是我们此刻讨论的
问题。
2.1.2 浮点数
数字符号(literal)是Perl 程序源代码中代替某个值的方法。数字符号不是计算或I/O 操作的结果,它是直接写进代码中的
数据。
Perl 语言入门(第四版)
22 / 201 9/21/2006
你可能已经很熟悉Perl 的浮点数。有或没有小数点的数字都是允许的(包括+或-号),也可带一个十进制的指数(符号为E)。
1.25
255.000
255.0
7.25e45 #7.25x10 的45 次方(一个大整数)
-6.5e24 # -6.5x10 的24 次方(一个大的负数)
-12e-24 #- -12x10 的-24 次方(很小的负数)
-1.2E-23 #指数符号可以大写(E)
2.1.3 整数
整数是简单明了的:
0
2001
-40
255
61298040283768
最后一个读起来有些困难。Perl 允许用下划线来分隔它,因此可以像下面这样书写:
61_298_040_283_768
它们是相同的值,但形式上有些不同。你可能认为逗号(,)更恰当,但逗号在Perl 中有其它用途(下一章中将介绍)。
2.1.4 非十进制整数
同许多其它语言一样,Perl 也允许使用非10 为底的数字。八进制以0 开头,十六进制以0x 开头,二进制0b 开头◆。在十
六进制中A 到F(或者a 到f)分别表示10 到15:
◆“前置0”指示符只对数字有效,对由字符串转换过来得数字无效,在本章后面你可以看到。可以利用oct()或hex()把某个看起来像八
进制或十六进制的数据串转换成数字。虽然没有“二进制”(bin)函数来转换二进制的值,如果某个字符串以0b 开头可由oct()做到。
0377 #八进制数字377,等同于十进制数字255
0xff #十六进制数字FF,等同于十进制数字255
0b11111111 #等同于十进制数字255
这些数字表面上看起来并不相同,但这三个数在Perl 中都代表同一个数。对于Perl 来讲,0 xFF 或255.00 是没有区别的,
因此选择一种你和你的程序维护者(我们是指那个要读懂你代码的可怜伙计。通常,这个可怜的家伙就是你,你很可能想
不起3 个月前,你为什么要那样做)认为最有意义的一种。
Perl 语言入门(第四版)
23 / 201 9/21/2006
当一个非十进制的数字超过4 位时,读起来将很困难。由于这个理由,Perl 允许你使用下划线来区分:
0x1377_0B77
0x50_65_72_7C
2.1.5 数字操作符
Perl 除了提供通常的操作符加(+),减(-),乘(*),除(/)等等之外:
2+3 #2+3,5
5.1-2.4 #5.1-2.4,2.7
3*12 #3*12,36
14/2 #14/2,7
10.2/0.3 #10.2/0.3,34
10/3 #通常是浮点除,3.33333… …
还提供了模数运算符(%)。10%3 的值是10 除以3 的余数。两个操作数首先变成它们对应的整数值,如10.5%3.2 转换为
10%3◆后再计算。另外,Perl 中提供了和FORTRAN 类似的指数操作符,C 和Pascal 很希望有类似的能力。这个操作符由
两个*号表示,如2**3,表示2 的3 次方,等于8◆。我们将在需要的地方介绍其它的数字操作浮。
◆注意,在模数运算中,如果有一个操作数为负数,那其结果和Perl 的具体实现相关。
◆通常不能进行一个负数的非整数次方的运算。对数学有一定了解的读者知道,这将产生一个复数(数学概念中的复数:如1+2i,译注)。
如果想进行类似的预算,你需要Math::Complex 这个模块
2.2 字符串
字符串是一串字符(如hello)。字符串可能是字符的任意组合◆。最短的字符串不含任何字符。最长的字符串,可以填满
整个内存。这符合Perl 的哲学,只要有可能就不加任何内嵌的限制。通常字符串是可打印字符,数字,标点符号的序列(从
ASCII 32 到ASCII 126)。但,Perl 中字符串可以包含任意字符,意味着利用字符串(string)你可以创建,遍历,操作二进制
数据,而利用别的方法可能遇到极大的困难。例如,你可以把要更新的图片或编译好的程序放入一个Perl 的字符串变量中,
做完相应的修改后,再写回去。
◆和C,C++不同,Perl 中NUL 字符没有特殊的含义。Perl 能计算长度,不用靠null 来判断字符串是否结束。
和数字一样,字符串也可由文字符号(literal)来表示,它用来在Perl 程序中代表某个字符串。有两种类型的字符串:单引号
字符串和双引号字符串。
Perl 语言入门(第四版)
24 / 201 9/21/2006
2.2.1 单引号字符串
单引号字符串是由单引号括起来的字符序列。单引号不是字符串的一部分,但Perl 可以利用它来辨别字符串的开始和结束。
除了单引号,或者反斜线(包括换行字符,如果字符串在下一行继续)之外的任何字符都表示它自身。要得到一个反斜线,
可以把两个反斜线放在一起;要得到单引号,需要在单引号前加上反斜线:
‘fred’ #四个字符:f,r,e,d
‘barney’#六个字符
‘’ #空字符(没有字符)
‘Don’t let an apostrophe end this string prematruely!’
‘the last character of this string is a backslash:
‘hello\n’#hello 紧跟着反斜线和n
‘hello
there’ #hello,换行,there (共11 个字符)
‘\’\\’ #单引号(’)跟着反斜线(\)
单引号字符串中的\n 不会被当作换行符来处理,其仅仅是两个字符\和n。只有在反斜线(\)后面接的是\或单引号’,其才会被
当作特殊符号来处理。
2.2.2 双引号字符串
双引号字符串和在其它语言类似。它也是字符的序列,不同点在于,其由双引号括起来的。现在,反斜线可以用来表示控
制字符,或者八进制,十六进制数的表示。下面是一些双引号字符串的例子:
“barney”#等同于‘barney’
“hello world\n”#hello world,换行
“the last character of this string is a quote mark:\””
“coke\tsprite”# coke, a tab(一个制表符), sprite
双引号中字符串“barney”和单引号字符串‘barney’相同。和数字一样,0377 只是255.0 的另一种写法。Perl 允许你以一种更
有意义的方式来书写。当然,如果想\和之后的字符成为转义字符(如\n 表示新行),应当使用双引号。
反斜线后接不同的字符其含义不同(通常称为:转义字符)。表2-1 基本上列出了所有的◆双引号中的转义字符。
◆最近Perl 中引进了Unicode 转移符,我们这里不演示它们
表2-1 双引号字符串中的转义符
符号含义
\n 换行
\r 回车
\t 制表符
Perl 语言入门(第四版)
25 / 201 9/21/2006
\f formfeed
\b 退格
\a 响铃
\e escape(ASCII 中的escape 字符)
\007 任何八进制值(这里是,007=bell(响铃))
\x7f 任何十六进制值(这里是,007=bell)
\cC 一个控制符(这里是,ctrl +c)
\\ 反斜线
\” 双引号
\l 下个字符小写
\L 接着的字符均小写直到\E
\u 下个字符大写
\U 接着的字符均大写直到\E
\Q 在non-word 字符前加上\,直到\E
\E 结束\L,\E 和\Q
双引号字符串另一个性质是可进行变量内插,这是说当使用字符串时,如果字符串中含有变量名,将由变量的当前值替换
它。我们还没有介绍变量,在本章的后面将继续讨论这个问题。
2.3.3 字符串操作符
字符串可由. 操作符连接(是的,只是一个点) 。它不会改变任何字串,就像2+3 不会改变2 或3 一样。串联之后的字符串
可供以后使用:
“hello”. “world” # 同于“helloworld”
“hello”. ‘’. “world”#同于“hello world”
‘hello world’. “\n” #同于“hello world\n”
串联必须由. 操作符进行。同别的语言不一样,串联可通过把两个放在一起来达到。
一个特殊的操作符是字符串重复操作符(string repetition operator),由小写的字母x 表示。这种操作能把操作符左边字符串
重复操作符右边数字那么多次:
“fred”x 3 # “fredfredfred”
“barney”x (4+1) # “barney”x 5, “barneybarneybarneybarneybarney”
5 x 4 #实际上是“5”x 4, “5555”
值得具体讲解下最后一个例子。字符串重复操作符需要一个字符串作为左操作数,因此数字5 被转变为字符串“5”(在一
节将详细讨论),一个单字符字符串。这个新的字符串被复制4 次,产生了一个4 字符的字符串5555。如将两个操作数的
顺序对调下:4 x 5,将得到字符串44444。这表示字符串重复操作符不是可交换的。
Perl 语言入门(第四版)
26 / 201 9/21/2006
复制次数(右操作数)在使用之前会把它转换为小于等于它的整数(如,4.8 变为4)。重复次数小于1 将产生空串(长度
为0)。
2.2.4 数字和字符串之间的自动转换
大多数情况下,Perl 将在需要的时候自动在数字和字符串之间转换。它怎样知道什么时候需要字符串,什么时候需要数字
呢?这完全依赖于标量值之间的的操作符。如果操作符(如+)需要数字,Perl 将把操作数当作数字看待。如果操作符需要
字符串(如. ),Perl 将把操作数当作字符串看待。不必担心数字和字符串的区别;使用恰当的操作符,Perl 将为你做剩下
的事。
当在需要数字的地方使用了字符串(如,乘法),Perl 将自动把字符串转换为其等价的数字,就像输入的是十进制浮点数一
样◆。因此“12”* “3”将给出36。后面的非数字部分和前面的空格将被去掉,如“12fred34”* “3”将给出36 而不会用任何
提示◆。在极端情形,当一个不含任何数字的字符串将别转换为0。如,将“fred”当作数字来使用时。
◆用首字符0 表示非十进制值对数字有效,对自动转换没有作用。使用hex()和ort()来转换此类字符串
◆除非你使用了warnings,我们将很快讨论到。
同样,如在需要字符串的地方使用了数字(如,字符串连接),数字将转换为字符串。例如,如果你想在Z 后串接5 乘以7
的结果◆,可以这样写:
“Z”. 5 * 7 #同于“Z”. 35,或“Z35”
总之,一句话,不用担心使用的是数字还是字符串(大多数情况下)。Perl 将自动转换它们◆。
◆不用担心效率问题。Perl 能记住转换的结果,因此这一步只做一次。
2.3 Perl 内嵌的警告(warnings)
当程序中包含可能的错误时,可以要求Perl 警告你。运行程序时,可以在命令行中使用–w 这个参数把警告打开:
$ perl–w my_program
或者,如果一直都需要警告(warning),可以在#! 这一行加上-w,如:
#! /usr/bin/perl –w
这条命令甚至在non-Unix 系统中也有效,由于在这些系统中通常与Perl 的具体路径关系不大,因此可如下书写:
Perl 语言入门(第四版)
27 / 201 9/21/2006
#! perl –w
在Perl5.6 或之后的版本中,可以使用pragma 来打开警告(warning).(注意,它对早期的Perl 版本无效)◆。
◆warnings progma 允许文字上的警告。你可以在pelllexwarn 的用户手册中找到详细信息。
#! /usr/bin/perl
use warnings;
现在,如果将‘12fred34’当作数字来用,Perl 将警告你:
Argument “12fred34”isn’t numeric
当然,警告通常只对程序员有意义,对普通用户则没什么用处。如果程序员没有看到警告(没使用警告),这并没什么好处。
警告除了在某些时候抱怨可能出错外,不会改变程序的行为。如果看到不能理解的警告信息,可以使用diagnostics pragma,
通过它可以看到更详细的信息。perldiag 的mangage 中有对短的warning(警告)和长的diagnostic(诊断)的描述。
#! /usr/bin/perl
use diagnostics;
当把use diagnostics 加入程序后,在每次调入程序时,它好象暂停了一会儿。那是因为Perl 做了大量的工作(占去大块内
存),使在当Perl 发现错误时,你能迅速的读其文档,如果有的话。这导致了一种对Perl 程序优化的方法,当不需要读警
告信息相关的文档时,将use diagnostics 去掉。(当然如果能修改程序,把引起警告的原因去掉,那是最好不过了。但只是
取消阅读这些文档已经足够。)
另一种优化方法是,在命令行中使用–M 这个参数,仅当需要diagnostics 时才用,而不用每次通过修改源代码来决定是否
激活diagnostics:
$ perl–Mdiagnostics ./my_program
Argument “12fred34”isn’t numeric in addition(+) at ./m_program line 17 (#1)
(Wnumeric) The indicated string was fed as an argument to
an operator that expected a numeric value instead. If you’re
fortunate the message will identify which operator was so unfortunate.
我们将指出代码中可能警告的地方。但在现今版本中的警告信息和将来版本可能不同。
2.4 标量变量
变量是保存一个或多个值的容器◆。变量的名字在整个程序中保持不变,但其包含的值可以变化。
◆如你所见,标量变量仅能还有一个值。但其它变量,如数组或哈希(hash),可以含有多个值。
标量变量可以存放一个标量值。标量变量的名字由一个美圆符号($)后接Perl 标识符:由字母或下划线开头,后接字母,
Perl 语言入门(第四版)
28 / 201 9/21/2006
数字,或者下划线。或者说由字母,数字和下划线组成,但不能由数字开头。大小写是严格区分的:变量$Fred 和变量$fred
是不同的。任意字母,数字,下划线都有意义,如:
$a_very_long_variable_that_ends_in_1
和变量:
$a_very_long_variable_that_ends_in_2
是不同的。
标量变量在Perl 中由$开头◆。在shell 中,当取值时,需要$;赋新值时,不需要$。在awk 和C 中,完全不需要$。如果
你在这这几种语言中来回切换的话,你很可能经常出错。这是很正常的。(大多数Perl 程序员推荐在写Perl 程序时停止书
写shell, awk,C 程序,当然是否采纳,由你自己决定)。
◆按照Perl 的行话来讲,被称作“sigil”。
2.4.1 选择好的变量名
通常,应当选择能很好描述你的意图的变量名。例如,变量$r 就不如$line_length 描述性强。如果一个变量只在相临几行中
使用,那可以取个像$n 这样的名字,但如果变量要在整个程序中使用的话,最好还是仔细的选择变量名。
同样的,仔细的使用下划线可以使变量名更易阅读和理解,特别是维护你程序的人和你有不同的母语背景时。例如,
$super_bowl 这个变量就比$superbowl 好些,因为后者可能被理解为$superb_owl。又如$stopid 是$sto_pid(保存一个进程ID),
还是$s_to_pid(将某个东西转变成进程ID),或是$stop_id(“stop”对象的ID),或者仅仅是$stupid 的错误拼写?
大多数Perl 程序中的变量都是小写的,和你在本书中见到的一样。在少数情况下,使用大写字母。所有字母均大写(如
$ARGV)通常表明这个变量有特殊的地方。当一个变量有超过一个单词时,一些人使用$underscores_are_cool 这种形式,
另一些人使用$giveMeInitilalCaps 这种形式。无论采取那种,请保持风格一致。
当然,变量名字的好坏对Perl 没有任何影响。如你可以把三个重要的变量命名为:$ooooooooo, $oooooooo, $oooooooooo,
Perl 不会弄错。但是,如果这样,请不要让我们维护你的代码。
2.4.2 标量赋值
标量变量最通常的操作是赋值:将值赋给变量。Perl 中的赋值符是等号(和许多语言类似),将等号右边的值赋给等号左边
的变量:
$fred = 17; #将17 赋给变量$fred
$barney =‘hello’; #将五个字母的字符串‘hello’赋给$barney
Perl 语言入门(第四版)
29 / 201 9/21/2006
$barney = $fred + 3;# 将$fred 的值加上三赋给$barney (20)
$barney= $barney*2;#将变量$barney 乘2 再赋给$barney (40)
注意最后一行中$barney 变量使用了2 次:一次从中取值(等号右边)一次作为赋值的对象(等号左边)。这是合法的,安
全的,且普遍使用。事实上它如此常用,以致Perl 提供了一种简便写法,你将在下一节中了解到。
2.4.3 二元赋值操作符
像$fred=$fred+3(同一个变量在赋值符两边出现)这样的表达式在Perl 中经常出现(同C 和Java 类似),因此Perl 提供了
一种简便的替代方法:二元赋值操作符。几乎每一个二元操作符都有一个等价的二元赋值形式:由这个符号后接等号组成。
例如,下面两行是等价的:
$fred = $fred + 5; #没有用二元赋值操作符
$fred+=5; #利用二元赋值操作符
下面的也是等价的:
$barney = $barney*3;
$barney*=3;
上述两例中,变量借助自身而非别的变量来改变自身的值。
另一个常用的赋值操作符是字符串连接符号(.);其赋值形式为(.=):
$str = str . “”; #$str 后接空格
$str .= “”’; #同上
2.5 print 输出
通常,应该让你的程序有输出,是一个好主意;否则,别人可能认为程序什么事也没做。print()能完成这种工作。它把一个
标量参数作为参数,再把它不做修改的输出来。除非做了某些修改,否则其默认的输出是终端(显示器):
print “hello world\n”; #输出hello world,后接换行符
print “The answer is ”;
print 6 * 7;
print “.\n”;
也可以将一串值赋给print,利用逗号分开:
print “The answer is ”,6*7, “.\n”;
Perl 语言入门(第四版)
30 / 201 9/21/2006
这是列表,但我们还没讨论到列表,这将以后解释。
2.5.1 字符串中标量变量的内插
当一个字符串由双引号括起来时,如果变量前没有反斜线,则变量会被其值内插◆。也就是说字符串中的标量变量◆将被
其值替换。
◆这和数学或统计学中的内插含义是不同的
◆还有一些其它的变量类型,在后面章节中将看到
$mean = “brontosaurus steak”;
$barney = “fred ate a $meal”; #$barney 现在是“fred ate a brontosaurus steak”
$barney = ‘fred ate a’. $meal; #同上
从上面得知,不使用双引号也可以得到相同的结果。但使用双引号更方便些。
如果一个变量未被赋值,则将使用空值替换:
◆这是一种特殊的未定义值,undef。在本章后面将介绍到。如果开启了警告,Perl 将提示你内插的变量未定义(未初始化)。
$barney = “fred ate a $meat”; #$barney 现在是“fred ate a ”;
如果使用的是单独一个变量,是否使用引号没有影响。如:
print “$fred”; #引号是没有必要的
print $fred; #更好的写法
将单独的一个变量使用引号括起来没有错误,但别的程序员可能会笑你◆。变量内插通常也叫做双引号内插,因为它在双
引号中(而非单引号)才有效。在某些别的字符串中也可能被内插,遇到它们时再讲解。
◆是的,可能将其值作为字符串而非数字看待。在极少数情况下,是需要引号的。但几乎大多数情况都是浪费笔墨。
在字符串中变量前($符号前)加上反斜线(\),变量将不会被内插(替换):
$fred = ‘hello’;
print “The name is \$fred .\n”; #打印出美圆符号,变量不会被其值替换
print ‘The name is $fred’. “\n”; #同上
变量名将是字符串中有意义的最长的那一个。这可能在当你需要在某次匹配就替换的情况下出问题。Perl 提供了一种类似
于shell 的分隔符:花括号({})。用花括号将变量名括起来。或者将字符串分隔成几个部分,再用连接符( . )串起来:
$what =“brontosaurus steak”;
Perl 语言入门(第四版)
31 / 201 9/21/2006
$n = 3;
print “fred ate $n $whats.\n”; #不是steaks,而是$whats 的值
print “fred ate $n ${what}s.\n”; #现在是使用变量$what
print “fred ate $n $what”. “s.\n”; #另一种方法
print ‘fred ate ’. $n . ‘’. $what . “s.\n”; #一种复杂的方法
2.5.2 操作符优先级和结合性
操作符的优先级规定哪部分先进行预算。例如,表达式2+3*4,是先进行加呢还是先进行乘?如果先进行加,得到5*4,20。
如果先进行乘(同数学课中学到的一样),将得到2+12,等于14。幸运的是,Perl 中的定义和数学上的一样,先进行乘。
由此,我们可以说乘法比加法的优先级更高。
可以使用括号来改变优先级。括号中的表达式将首先被计算(和数学课中学到的一样)。因此,如果想加法先进行,可以使
用(2+3) * 4,得到20。如果想先进行乘,可以使用2 + (3*4),当然此时括号不是必需的。
乘法和加法的优先级是比较容易确定的,但字符串连接符和幂运算的优先级就不是那么明显的。恰当的方法是查看Perl 的
优先级表,如表2-2◆.(一些操作符没在此表中列出,要查看详细信息,可参考Perl 的用户手册)。
◆C 和Perl 中都有的操作符有相同的优先级,这对C 程序员是一个好消息。
表2-2 操作符的优先级和结合性(由高到低)
结合性操作符
左括号和列表操作符的参数
左->
++ --(自增和自减)
右**
右\ ! ~ + - (一元操作符)
左=~ !~
左* / % x
左+ - . (二元操作符)
左<< >>
Named unary operators (-X filetests, rand)
< <= > >= lt le gt ge(“不等的”)
= = != <=> eq ne cmp(“相等的”)
左&
左| ^
左&&
左||
.. …
右?:(三元操作符)
Perl 语言入门(第四版)
32 / 201 9/21/2006
右= += -= .=
左, =>
List operators(rightward)
右not
左And
左or xor
上表中,上面的操作符比下面的操作符优先级更高。同一优先级的操作符由结合性来决定计算顺序。
同优先级类似,结合性是用来规定有相同优先级的操作符的计算顺序:
4** 4** 2 #4**(3**2)
72/12/3 #(72/12)/3
36/6*3 #(36/6)*3
在第一条中,**是右结合的,所以右边的先进行计算。同样的,由于* /是左结合的,所以左边的先进行运算。
那么,需要记住优先级表吗?不需要!事实上没有人那样做。如果记不住优先级时,可以使用括号。毕竟,如果你不知道
其优先级顺序,那很可能程序的维护者也记不住。因此,应当善待他/她,因为那个人很可能就是你!
2.5.3 比较运算符
对于数字的比较,Perl 提供了< <= = = >= != 这些操作符。每一种返回的值为true 或者false。在下一节中将了解到
更多。其中一些可能和你在别的语言中学到的不一样。例如:= = 相等;= 赋值;!= 不等,因为<>在Perl 中有别的用途。
使用>= 而非=> 作为“大于等于”,也是由于=> 有其它用途。事实上,绝大多数符号的组合在Perl 中都是有特殊用途
的。
对于字符串比较,Perl 有如下的一些有趣的字符串比较符:lt le eq ge gt ne。它们将一个字符接着一个字符的比较两个串来
判断它们的关系:相等,小于,等等。(注意,在ASCII 中,大写字母在小写字母的前面)。
比较运算符(数字的和字符串的),列在表2-3 中。
表2-3 数字和字符串的比较运算符
比较关系数字字符串
相等= = eq
不等!= ne
小于< Lt
大于> gt
小于或等于<= le
大于或等于>= ge
下面是一些关于比较运算符的例子:
Perl 语言入门(第四版)
33 / 201 9/21/2006
35 != 30+5 #false
35 == 35.0 #true
‘35’eq‘35.0’ #false (按照字符串比较)
‘fred’lt ‘barney’ #false
‘fred’lt ‘free’ #true
‘fred’eq ‘fred’ #true
‘fred’eq ‘Fred’ #false
‘’gt ‘’ #true
2.6 if 控制结构
一旦能比较两个值时,就希望能根据这些比较结果作判断。和别的语言类似,Perl 中也提供了if 控制结构:
if($name gt ‘fred’){
print “‘$name’comes after ‘fred’in sorted order.\n”;
}
如果需要另一种选择,可以使用关键字else:
if($name gt ‘fred’){
print “‘$name’comes after ‘fred’in sorted order.\n”;
}else{
print “‘$name’does not come after ‘fred’.\n”;
print “Maybe it’s the same string, in fact.\n”;
}
花括号是必须的(这一点和C 不同)。将块中的代码缩进是一个好主意;这样将使代码易于阅读。如果使用的是程序员编
辑器(参见第一章),它将为你自动完成许多事。
2.6.Boolean 值
在if 控制结构的条件判断部分可以使用任意的标量值。这在某些时候将很方便,如:
$is_bigger = $name gt‘fred’;
if($is_bigger){… }
那么,Perl 是怎么判断其值得true 或false 呢?Perl 不同于其它的一些语言,它没有Boolean 类型。它利用如下几条规则◆:
◆事实上Perl 不是用的这些规则,但你可以利用它们方便记忆,其结果是一致的。
Perl 语言入门(第四版)
34 / 201 9/21/2006
● 如果值为数字,0 是false;其余为真
● 如果值为字符串,则空串(‘’)为false;其余为真
● 如果值的类型既不是数字又不是字符串,则将其转换为数字或字符串后再利用上述规则◆。
◆这意味着undef(很快会看到)为false。所有的引用(在Alpaca 书中有详细讨论)都是true。
这些规则中有一个特殊的地方。由于字符串‘0’和数字0 有相同的标量值,Perl 将它们相同看待。也就是说字符串‘0’是唯一
一个非空但值为0 的串。
如果想得到相反的值,可以使用一元非运算符! 。如果其后面的是true,则得到false;反之,则得到true:
if(! $if_bigger){
#当$if_bigger 非真时,运行此代码
}
2.7 用户输入
现在,可能想你的Perl 程序怎样才能从键盘上得到输入呢?有一种简单方法:使用行输入操作符(line-input operator),
◆。
◆是行输入运算符对文件句柄STDIN 的操作。但直到第五章才介绍文件句柄。
作为标量值来使用的,Perl 每次从标准输入中读入文本的下一行,将其传给。标准输入可以有很多种;
默认的是键盘。如果还没有值输入,Perl 会停下来等你输入一些字符,由换行符结束(return)◆。
◆坦白讲,是你的系统等待输入,Perl 等待你的系统。具体的细节与机器和配置有关。由于是系统而非Perl 控制你的输入,因此要更正错
误的输入通常可以在按下回车前使用退格键(backspace)。如果想更多的控制输入,可以使用Term::ReadLine 这个模块,在CPAN 中可
以下载到。
中的字符串通常由一个换行符作为结尾◆。因此,可以如下操作:
◆例外的情况是,标准输入流在行中间就结束了。当然,普通的文本文件通常不是这样。
$line = ;
if($line eq “\n”){
print “That was just a blank line!\n”;
}else{
print “That line of input was: $line”;
}
实际上,通常你不需要保留换行符,因此需要chomp 来去掉它。
Perl 语言入门(第四版)
35 / 201 9/21/2006
2.8 chomp 操作
第一次读到chomp 函数时,它看起来过于专门化。它对变量起作用,而此变量含有字符串。如果字符串结尾有换行符,chomp
可以去掉它。这基本上就是它能完成的所有功能,如下例:
$text = “a line of text\n”; #也可以由输入
chomp($text); #去掉换行符(\n)。
它非常有用,基本上你的每一个程序都会用到它。如你将知道,这是将字符串末尾换行符去掉的最好方法。基于Perl 中的
一条基本原则:在需要使用变量的地方,可以使用赋值表达式来代替。我们有更简单的使用chomp 的方法。Perl 首先做赋
值运算,再使用这个变量。因此使用chomp 的最常用方法是:
chomp ($text = ); #读入,但不含换行符
$text = ;
chomp ($text); #同上,但用两步完成
第一眼见到时,第一种组合的方法看起来复杂些。如果把上述其看成两步操作,读一行再chomp,那写成两个语句的方法
看起来自然些。如果将其看作一个操作,读入一行但不包括换行符,那写成一个语句的方法更恰当。由于绝大多数Perl 程
序员使用第一种写法,你也应该使用它。
chomp 是一个函数。作为一个函数,它有一个返回值,为移除的字符的个数。这个数字基本上没什么用:
$food = ;
$betty = chomp $food; #得到值1
如上,在使用chomp 时,可以使用或不使用括号()。这又是Perl 中的一条通用规则:除非移除它们时含义会变,否则括
号是可以省略的。
如果结尾有两个或两个以上的换行符◆,chomp 仅去掉一个。如果没有,那什么也不做,返回0。
◆这种情况在一次读入一行时不会发生,但使用了输入分隔符(input separator)($/)(其不为换行符(\n)),read 函数,或者将一些字符串结
合起来就有可能发生。
2.9 while 控制结构
和许多的程序语言一样,Perl 也提供了循环结构◆。while 语句可以循环执行其内部的一块代码直到其条件非真:
◆基本上每个程序员都有创建过无限循环语句的经历。如果程序不停的运行,你可以像关闭系统中别的程序那样来关闭Perl 程序。通常
是使用CTRL+C;检查你的系统文档来了解具体的信息。
Perl 语言入门(第四版)
36 / 201 9/21/2006
$count = 0;
while ($count < 10) {
$count + = 2;
print “count is now $count\n”; #打印出2 4 6 8 10
}
条件中真假值的判断和if 结构中是一样的。和if 控制结构相同,花括号是必须的。判断条件在迭代前执行,如果条件为假,
则一次也不执行。
2.10 undef 值
在变量被赋值之前使用它会有什么情况发生呢?通常不会有什么严重的后果。变量在第一次赋值前有一个特殊值undef,按
照Perl 来说就是:“这里什么也没有,请继续”。如果这里的“什么也没有”是一些“数字”,则表现为0。如果是“字符串”,
则表现为空串。但undef 既非数字也非字符串,它是另一种标量类型。
由于undef 在需要数字的地方可以自动转化为0,因此可以如下的写代码:
#将一些基数相加
#n = 1;
while($n < 10){
$sum += $n;
$n +=2;#下一个奇数
}
print “The total was $sum.\n”;
上述代码在$sum 未初始化(undef)时也能正确执行。第一次执行时,循环体中第一行$n 值为1,因此将1 加给$sum。而$sum
就像已经有值0,因为$sum 值为undef。现在其值1。之后,由于其已被初始化,其过程同普通的类似。
同样的,针对字符串的情形:
$string .= “more text\n”;
如果$string 为undef;则是空串后接“more text\n”。反之,则是其值后接“more text\n”。
Perl 程序员在使用新变量时,经常不初始化,从而将变量作为0 或者空串使用。
许多操作当参数不恰当时返回undef。如果没做特殊处理,通常会得到0 或者空串。实践中,这几乎不会有什么问题。实际
上,许多程序员利用这种性质。但应当知道如果警告是打开的,那Perl 在你不恰当的使用未定义值时会提醒你。例如,将
一个undef 的变量赋给另一个变量不会有什么问题,但如果print 某个未定义的值则将引起警告。
Perl 语言入门(第四版)
37 / 201 9/21/2006
2.1.1 defined 函数
能返回undef 的操作之一是行输入操作,。通常,它会返回文本中的一行。但如果没有更多的输入,如到了文件
的结尾,则返回undef◆。要分辨其是undef 还是空串,可以使用defined 函数,它将在为undef 时返回false,其余返回true。
◆事实上,从键盘输入,不会有“end-of-file”,但其可重定向到文件中再输入。或者用户可能输入某些键,而系统将其作为end-of-file 看待。
$madonna = ;
If ($defined ($madonna)){
print “The input was $madonna”;
}else{
print “No input available!\n”;
}
如果想声明自己的undef 值,可以使用undef:
$madonna = undef ; #同$madonna 从未被初始化一样。
2.1.2 练习
答案请参考附录A:
 [5]写一个程序,计算半径为12.5 的圆的周长。圆周长等于2(约为)乘以半径。答案为。

2. [4]修改上述程序,用户可以在程序运行时输入半径。如果,用户输入12.5,则应得到和上题一样的结果。
3. [4]修改上述程序,当用户输入小于0 的数字时,程序输出的周长为0,而非负数
4. [8]写一个程序,用户能输入2 个数字(不在同一行)。输出为这两个数的积
5. [8]写一个程序,用户能输入1 个字符串和一个数字(n)(不在同一行)。输出为,n 行这个字符串,1 次1 行(提示,使
用“x”操作符)。例如,如果用户输入的是“fred”和“3”,则输出为:3 行,每一行均为fred。如果输入为“fred”和
“299792”,则输出为299792 行,每一行均为fred。
Perl 语言入门(第四版)
38 / 201 9/21/2006
第三章列表和数组
如果把标量认为是Perl 中的单数的话,如我们在第二章开头讨论的,那列表(list)和数组则可认为是Perl 中的复数。
列表是标量的有序集。数组是包含列表的变量。在Perl 中这个两个术语是可以互换的。但严格意义上讲,列表是指数据,
而数组是其变量名。可以有一些值(列表)但不属于数组;但每一个数组标量都有一个列表,虽然其可以为空。图3-1 是
一个列表,无论其是否存储在一个数组中。
图3-1 一个有五个元素的列表



列表中每一个元素都是一个独立的标量值。这些值是有顺序的,也就是说,这些值从开头到最后一个元素有一个固定的序
列。数组或者列表中的元素是编了号的,其索引从整数0 开始◆,依次增一,因此数组或者列表第一个元素的索引为0。
◆数组或者列表在Perl 中的索引总是从0 开始,这和某些语言不同。在Perl 的早期版本中,是可以改变数组列表初始索引值的(不只对一
个数组或列表而是一次针对所有的)。Larry 后来发现这是个错误的功能, 其应用也让人失望。但是,如果你特别感兴趣的话,可以参
看perlvar 用户手册中的$[变量。
由于每一个元素是一个独立的标量值,因此一个列表或者数组可以包含数字,字符串,undef 值,或者任意不同类型的标量
值的组合。然而,这些元素的类型通常是一致的,例如关于书名的列表(值均为字符串),关于余弦的列表(值均为数字)。
列表和数组可以包含任意数量的元素。最少含有0 元素,最多可以填满你的可用内存。这里又体现了Perl 的设计哲学,“没
有不必要的限制”。
0 35
1 12.4
2 “hello”
3 1.72e30
4 “bye\n”
Perl 语言入门(第四版)
39 / 201 9/21/2006
3.1 访问数组元素
如果你使用过其它语言的数组,那对于Perl 可以通过索引值来访问元素的做法不会觉得奇怪。
数组中的元素是由连续整数编了号的,其从0 开始,每增加一个元素,其索引值加一,如:
$fred[0] = “yabba”;
$fred[1]= “dabba”;
$fred[2] = “doo”;
数组名字(本例中:fred)和标量是属于完全不同的命名空间(namespace)。同一程序也可以同时包含叫做$fred 的标量变
量。Perl 将它们当作完全不同的事物来看待,不会混淆◆。(但维护人员可能混淆,所以最好不要将它们以相同的名字来命
名)。
◆语法总是无二义性的;也许有些技巧,但是确定的。
可以在任何◆能够使用标量变量(如$fred)的地方使用数组元素(如$fred[2])。例如,可以使用上一章介绍的方法来获得
数组元素的值,或者改变它。
◆实际上是绝大多数。最明显的例外是foreach 循环中的控制变量(在本章后面将介绍到), 必须是标量变量。还有些例外,如print 和printf
的“indirect object slot”和“indirect filehandle slot”。
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
3.2 特殊的数组索引
如果将一个元素存储在数组最后元素的后面的位置,数组会自动增长的。Perl 没有长度的限制,只要你有足够的内存。如
果Perl 需要创建元素,则其值为undef。
$rocks[0] = ‘bedrock’; #一个元素
Perl 语言入门(第四版)
40 / 201 9/21/2006
$rocks[1] = ‘slate’; #又一个
$rocks[2] = ‘lava’; #又一个
$rocks[3] = ‘crushed rock’;#又一个
$rocks[99] = ‘schist’; #现在有95 个undef 元素
有时需要知道数组最后一个元素的索引。刚才使用的rocks 数组,其最后一个元素的索引为$#rocks◆。这和数组中元素的
个数是不同的,因为数组中包含元素0。(换句话说,最后一个元素的索引值要比其实际包含的元素个数少一,译者注)。
◆这种糟糕的语法来源于C shell。庆幸的是,在实际的代码中并不常见。
$end = $#rocks; #99,最后一个元素的索引
$number_of_rocks = $end + 1; #正确,但有更好的方法
$rocks[$#rocks] = ‘hard rock’; #the last rock
由于经常将$#name 的值作为索引,像上面例子那样,因此,Larry 提供了一种简便方法:数组的负数索引值从最后一个元
素开始。但不要认为这些索引是循环的。如果数组有3 元素,那有效的负数索引值是-1(最后一个元素),-2(中间的元素),
-3(第一个元素)。实际上,几乎没有人使用除了-1 之外的其它的负数索引值。
$rocks[-1] = ‘hard rock’; #完成上例中的一种更简单的方法
$dead_rock = ‘rocks[-100]’; #得到‘bedrock’,第0 个元素
$rocks[-200] = ‘crystal’; #严重错误(fatal error!)
3.3 列表
数组是由括号括起来并且其元素由逗号分隔开的列表。这些值组成了数组的元素:
(1,2,3) #含有1,2,3 的列表
(1,2,3,) #同上,最后一个逗号被忽略
() #空列表-0 个元素
(1 ..100) #包含100 个整数的列表
最后一个例子使用了范围操作符(range operator)..,它创建了从左值到右值之间所有值的列表。
(1 ..5) #同(1,2,3,4,5)
(1.7..5.7) #同上— 最小值和最大值被转换成整数
(5 ..1) #空列表— ..中的左值应小于右值,否则为空
(0,2 .. 6,10,12)#同(0,2,3,4,5,6,10,12)
($m ..$n) #由$m 和$n 的值决定
(0 .. $#rocks) #上节中有$#rocks 的介绍
从上面最后两个例子中可以看到,列表中的元素并非必须是常数,也可以是在执行此语句时再计算值的表达式:
($m,17) #两个值;$m 的当前值,和17
Perl 语言入门(第四版)
41 / 201 9/21/2006
($m+$o,$p+$q) #两个值
当然,列表可以包含任意的标量值,如下面的包含字符串的例子:
(“fred”, “barney”, “betty”, “wilma”, “dino”)
3.3.1 qw 简写
实践表明,字符串的列表(如上例)在Perl 中经常使用。有一种简便的方法可以不用输入大量的引号而达到类似的功能,
那就是使用qw。
qw(fred barney betty wilma dino ) #同上,但输入更少
qw 表示“quoted words”或者“quoted by whitespace,”这依赖于你问的是谁。无论那种解释,Perl 将它们当作单引号字符串
处理,你不能像双引号那样在qw 中使用\n 和$fred。whitespace(空格,像spaces,tabs,newlines 等字符串)将被忽略,剩下
的组成了列表的元素。由于空格被忽略,所以下面(不常用的)是另一种书写方法:
qw(fred
barney betty
wilma dino) #同上,当看起来有些奇怪
由于qw 是一种引用,因此不可以在qw 内添加注释。
前面两个例子是用括号作为分界符,但Perl 允许使用任何标点符号作为分界符。下面是一些常用的类型:
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 excite lycos ! #其中一个元素为:字符串yahoo!
同单引号字符串一样,两个反斜线,可以得到一个反斜线。
正如Perl 格言中所说: 做一件事不只一种方法(“There’s More Than One Way To Do It”),你可能猜想为什么有人需要这些不
同的方法。在后面你将看到许多此类的例子,它们非常有用。如我们处理Unix 中的文件名:
Perl 语言入门(第四版)
42 / 201 9/21/2006
qw{
/usr/dict/words
/home/rootbeer/.ispell_english
}
如果斜线(/)是唯一的分界符时,那么上述例子将变得极其繁琐。
3.4 列表赋值
和标量值类似,列表值也可以赋给变量:
($fred, $barney, $dino) = (“flintstone”, “rubble”, undef);
左边列表中的每一个变量都得到了一个新值,和利用3 个赋值语句得到的结果是一样的。由于列表在赋值之前已经建立,
因此在Perl 中可以使用如下的简单方法交换两个变量的值◆:
◆和C 语言不同,在C 语言中没有完成此类操作的简单方法。C 程序员通常需要使用临时变量,可能是使用宏(macro)来定义的。
($fred, $barney) = ($barney, $fred) #交换两个变量
($betty[0],$betty[1]) = ($betty[1],$betty[0]);
如果变量个数(等号左边)不同于其值的个数(等号右边),将发生什么事情呢?在列表赋值中,额外的值会被自动忽略。
因为Perl 认为,如果需要把值存起来,那应当指明其存储的地方。同样,如果有多余的变量,额外的变量被赋予undef◆。
◆对于标量变量这是对的。对于数组变量将得到空的列表,在后面将看到。
($fred, $barney) = qw ; #两个值被忽略了
($wilma,$dino) = qw[flintstone]; #$dino 为undef
现在可以给列表赋值了,可以使用如下的一行代码来创建按一个字符串数组◆:
◆我们假设rocks 在本语句之前是空的。如果之前的$rocks[7]非空。那,这个赋值语句将不会改变其值。
($rocks[0],$rocks[1],$rocks[2],$rocks[3]) = qw/talc mica feldspar quartz/;
当想引用这个数组时,Perl 有一种简单的写法。在数组名前加@(后没有中括号)来引用整个数组。你可以把他读作“all of the
(所有的)”,所以@rocks 可以读作“all of the rocks(所有的石头)”◆。其在赋值运算符左右均有效:
◆Larry 声称选择美元符号($)和@符号的原因是,可以分别读做$calar(scalar)和@arry(array)。你如果不能按这种方式来记忆,也无所谓。
@rocks = qw / bedrock slate lava /;
@tiny = (); #空表
@giant = 1..1e5; #包含100,000 个元素的表
@stuff = (@giant, undef, @giant); #包含200,001 个元素的表
Perl 语言入门(第四版)
43 / 201 9/21/2006
@dino = “granite”;
@quarry = (@rocks, “crushed rock”, @tiny, $dino);
最后一个赋值语句将五个元素(bedrock, slate, lava, crushed, rock, granite)赋给变量@quarry,因为@tiny 没有元素。(特别的
是,它没有undef 这个值,但可以像@stuff 那样明确的指定它。)还有一点需要注意的是数组名字被其列表值替换。数组不
能成为列表的一个元素的原因是数组只能包含标量值,不能包含其它的数组◆。没有赋值的数组变量的值为( ),空表。和
未初始化的标量变量为undef 类似,未被初始化的数组为空表。
◆但在Alpaca 书中,将介绍一类特殊的变量:引用。通过它可以造出被称为“lists of lists”(列表的列表)的数据结构,还有一些别的有用或
者有趣的结构。即便是那种情况,也不是将一个列表存放在一个列表之中,事实上存放的是其引用。
当将一个数组拷贝到另一个数组时,仍然是列表赋值。如下例:
@copy = @quarry; #将一个数组中的值拷贝的另一个数组中
3.4.1 pop 和push 操作
可以使用新的,更大的索引(index)将新值存放在数组的末尾。但实际上,Perl 程序员不使用索引◆。因此,在下面几段中,
我们将介绍几种不使用索引来操作数组的方法。
◆当然,我们是在开玩笑,但这个玩笑基于Perl 的一些事实。数组中使用索引并没有发挥Perl 的威力。如果使用pop, push 和类似的操作
符以避免使用索引,那你的程序通常会比大量使用索引的情况要快,而且能避免“差一位(off-by-one)”类型的错误,这类错误通常叫做“边
界值错误”。有时,一个初级的Perl 程序员(想比较Perl 和C 的速度)将针对C 优化过的排序程序(有大量的索引操作),用Perl 来直
接实现(从而有大量的索引操作),惊讶于它为什么如此慢。答案是,“用小提琴来订钉子不是一个好办法”。
通常将数组类似于栈来使用,在其右边添加或者删除数据。(这是数组中“最后”一个元素,其索引最大)。这些操作经常
出现,因此提供了特殊的函数。
pop 操作将数组的最后一个元素取出并返回:
@array = 5..9;
$fred = pop(@array); #$fred 得到9,@array 现在为(5,6,7,8)
$barney = pop @array; #$barney gets 8, @array 现在为(5,6,7)
pop @array; 现在为(5,6)(7 被丢弃了)
最后一个例子中,pop 使用在“in a void context”,也就是说没有存放其返回值的地方。这样使用pop 是合法的。
如果数组为空,那pop 什么也不做(因为没有元素可以移出),并返回undef。
你可能已注意到pop 后可以使用或者不使用括号。这在Perl 中是一条通用规则:如果去掉括号含义不变,那括号就是可选
的◆。和pop 相反的操作是push,它可以将一个元素(或者一列元素)加在数组的末尾:
Perl 语言入门(第四版)
44 / 201 9/21/2006
◆受过相应教育的人将发现,这是同义反复。
push(@array,0); 现在为(5,6,0)
push @array,8; 现在为(5,6,0,8)
push @array,1..10; 现在多了10 个元素
@others =qw/9 0 2 1 0 /;
push @array,@others; 现在又多了5 个元素(共有19 个)
push 的第一个参数或者pop 的唯一参数必须是数组变量。
3.4.2 shift 和unshift 操作
push 和pop 对数组的末尾进行操作(或者说数组右边有最大下标的元素,这依赖于你是怎样思考的)。相应的,unshift 和
shift 对一个数组的开头进行操作(数组的左端有最小下标的元素)。下面是一些例子:
@array = qw# dino fred barney #;
$m = shift (@array); #$m 得到“dino”, @array 现在为(“fred”, “barney”)
$n = shift @array; #$n 得到”fred”, @array 现在为(“barney”)
shift @array; 现在为空
$o = shift @array; #$o 得到undef, @arry 仍为空
unshift(@array,5); 现在为(5)
unshift @array,4; 现在为(4,5)
@others = 1..3;
unshift @array, @others; #array 现在为(1,2,3,4,5)
和pop 类似,如果其数组变量为空,则返回undef。
3.5 将数组插入字符串
和标量类似,数组也可以插入双引号的字符串中。插入的数组元素会自动由空格◆分开:
◆分隔符是变量$’’的值,其默认值为空格(space)。
@rocks = qw{ flintstone slate rubble };
print “quartz @rocks limestone\n”; #输出为5 种rocks 由空格分开
插入的数组元素的第一个元素前面和最后一个元素后面不会插入空格,如果需要可以自己加入:
print “Three rocks are: @rocks.\n”;
print “There’s nothing in the parens (@empty) here..\n”;
如果忘了数组插入的规则,当把email 地址插入双引号字符串时可能出现意想不到的结果。由于历史原因◆,这将引起编
Perl 语言入门(第四版)
45 / 201 9/21/2006
译时的严重错误:
◆你可能会问:在Perl5 之前,Perl 将不会替换没有定义过的数组标量。因此,” 将表示email 地址。但当某人加入了一
个变量@bedrock;则这字符串将变成“fred.edu”或者更糟。
$email ”; #错误!将会替换@bedrock
$email =“fred\@bedrock.edu”; #正确
$email ; #另一种方法
因此,在即将发行的Perl5(现在快发行Perl6 了:译者注),没有定义的数组变量的行为和没有定义的标量变量行为一致,
也就是说,当警告打开时,没有初始化的数组变量将引起警告。这是Perl 开发者10 年来经历的错误的结果。
只有一个元素的数组的被其值替换的行为和你预期的类似:
@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”; #同上
索引表达式被当作普通表达式求值,看起来和不在字符串中是一样的。其变量不会首先被赋值的。换句话说,如果$y 为“2*4”,
那上述表达式的值为1,而非7,因为“2*4”首先当作数字时($y 在数字表达式中)为2◆。如果想在一个标量变量后接一
个左中括号符,那应当在其间加入分隔符,否则会被作为数组看待:
◆当然,当把警告打开时,Perl 会提醒你“2*4” 是一个funny-looking 数字。
@fred = qw(eating rocks is wrong);
$fred = “right”; #我们将打印“this is right[3]”
print “this is $fred[3]\n”; #打印出“wrong”使用$fred[3]
print “this is ${fred}[3]\n”; #打印出“right”(由花括号分开)
print “this is $fred”. “[3]\n”; #正确(两个字符串,右. 分开)
print “this is $fred\[3]\n”; #正确(利用反斜线转义)
3.6 foreach 控制结构
如果能处理整个数组或列表,那将是非常方便的,因此Perl 提供了这种方法。foreach 从列表的第一个元素一直循环执行到
最后一个元素,一次迭代一个:
foreach $rock (qw/ bedrock slate lava /){
print “One rock is $rock.\n”; #打印出3 种rocks
}
控制变量(本例中为$rock)每一次迭代从列表中取出一个新值。第一次为“bedrock”,第三次为“lava”。
Perl 语言入门(第四版)
46 / 201 9/21/2006
控制变量不是这些列表元素中的一个拷贝而是这些元素本身。也就是说,如果在循环中修改这个变量,那原始列表中的元
素也会被修改,如下面代码段所显示。这条性质是有用的,但是,如果不清楚,可能对其结果感到吃惊。
@rocks = qw/ bedrock slate lava /;
foreach $rocks(@rocks){
$rock = “\t$rock”; 的每一个元素前加入一个tab
$rock . = “\n”; #每一个元素后加一个换行符
}
print “The rocks are:\n”,@rocks; #每一个元素都被缩进了,并且一个元素占一行
当循环结束时$rock 的值为多少呢?其值同循环开始之前相同。foreach 循环中控制变量的值会被Perl 自动保存和恢复。当
循环进行时,是没有办法改变其值的。循环结束时,变量的值会回到循环开始前,如果没有值则为undef。这意味着如果有
一个变量和控制变量有相同的名字:“$rock”,不用担心会混淆它们。
3.6.1 Perl 最常用的默认变量:$_
如果在foreach 循环中省略了控制变量,那Perl 会使用其默认的变量:$_。除了其不寻常的名字外,这和普通变量类似,如
下面代码所示:
foreach(1..10){ #使用默认的变量$_
print “I can count to $_!\n”;
}
虽然它不是Perl 中唯一的默认变量,但无疑是使用的最普遍的。你将在许多例子中看到Perl 在没有要求它使用某个变量或
值时,会自动使用变量$_,这将节约程序员大量的时间来思考使用哪一个变量。为了消除你的疑虑,下面的print,就是使
用$_的一个例子:
$_ =“Yabba dabba doo\n”;
print; #打印出默认变量$_。
3.6.2 reverse 操作
reverse(逆转)操作将输入的一串列表(可能是数组)按相反的顺序返回。如果不喜欢范围操作符: ..,只能从小到大,
那可以使用reverse 来解决这个问题:
@fred = 6 ..10;
@barney = reverse (@fred); #得到10,9,8,7,6
@wilma = reverse 6 ..10; #同上,没有使用额外的数组
@fred = reverse @fred; #将逆转过的字符串存回去
注意最后一行,其中@fred 使用了2 次。Perl 通常先计算变量的值(赋值号右边),再进行赋值。
Perl 语言入门(第四版)
47 / 201 9/21/2006
注意reverse 返回逆转的列表,它不会改变其参数的值。如果返回值没有赋值给某个变量,那这个操作是没有什么意义的:
reverse @fred; #错误,没有改变@fred 的值
@fred = reverse @fred; #改变了@fred 的值
3.6.3 sort 操作
sort 操作将输入的一串列表(可能是数组)根据内部的字符顺序进行排序。如对于ASCII 字符串,将根据ASCII 序进行排
序。当然,ASCII 中有一些奇怪的地方,如大写字母在小写字符的前面,数字在字符的前面,而标点符号散布在各处。但
按ASCII 排序只是其默认的行为,在第十三章中,可以看到如何按你想要的顺序进行排序的方法:
@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
从最后一个例子可以看到,如果将数字按照字符串进行排序可能得到没有意义的结果。当然,默认的排序规则下,任何由
1 开头的字符串先于由9 开头的字符串。和reverse 一样,其参数是不会受到影响的。如果想将某个数组排序,那必须将排
序之后的结果存回数组中:
sort @rocks; #错误,不会修改@rocks
@rocks = sort @rocks; #现在@rocks 值是经过排序的
3.7 标量和列表上下文
本节是本章中最重要的章节。事实上,是整本书的最重要一节。可以毫不夸张地说,你的整个Perl 职业生涯都是建立在对
本节的理解之上。如果之前的章节你都未认真阅读,那本章千万不能马虎。
但这并非说本节难于理解。本节仅是一个简单的概念:一个给定的表达式在不同的上下文中其含义是不同的。这本身没什
么新奇的地方;事实上这在自然语言中是司空见怪的。例如,在英语中◆,假设某人问你“read”◆的含义。它的具体含义
和你怎样使用它有关。除非你知道它使用的上下文环境,否则不知道其确切的含义。
◆如果英语不是你的母语,那这个类比可能对你不太明显。但上下文相关在任何语言中都存在,因此可以在你自己的母语中找到这样类
似的例子。
◆抑或它们问的是“red”的含义,如果他们是嘴上说的。无论哪种情况,其含义都是不确定的。如Donglas Hofstadter 所言,没有一种语
言可以把每一种思想都明白无误的表达出来,特别是本句话。
上下文是指表达式存在的地方。当Perl 解析表达式时,它通常期望一个标量值或者列表值◆。这既称为表达式的上下文环
Perl 语言入门(第四版)
48 / 201 9/21/2006
环境◆。
◆当然,也可能是别的类型。还有些别的contexts 没有在此处给出。没有人知道Perl 中使用了多少种contexts;Perl 社区中的首脑人物在
这个问题上也没一致答案。
◆这和人类语言中使用的情况类似。如果犯了语法错误,那很快会被发现,因为你知道在特定的地方使用特定的词。最终,你将用这种方
法来阅读Perl,但首先应该以这种方式来思考。
42 + something #something 必须是标量
sort something #something 必须是列表
如果something 是相同的字符串,在一种情况下,它返回一个变量值,在另一种情况下,它可能返回列表◆。Perl 中的表达
式将根据其context 返回适当的值。例如,一个数组的“name◆”,在列表context 中,它返回列表元素;在标量context 中,
它返回数组元素的个数:
◆当然这个列表可能只包含一个元素。也可能为空,或者包含任意数量的元素。
◆数组@people 的真实名字是people。@只是一个限定词(qualifier)。
@people = qw( fred barney betty );
@sorted = sort @people; #列表context:barney , betty, fred
$number = 42 + @people; #标量context:42+3,得到45
甚至普通的赋值(赋给标量或者列表)也产生不同的contexts:
@list = @people; #3 个People 的列表
$n = @people ; #数字3
不要得到这样的结果:在标量context 中能返回元素的个数,在列表context 中就一定返回这些元素。许多list-producing 的
表达式◆将返回一些更有趣的结果。
◆对于本节, “list-producing”表达式和“scalar-producing”是没有多少区别的。任何表达式都可以产生标量或者列表,这依赖其context。因
此,当我们说“list -producing expressings”,我们是指那些通常在列表context 中使用的表达式,当其在标量环境中使用时可能产生意想不
到的结果(如reverse 或者@fred)。
3.7.1 在标量Context 中使用List-Producing 表达式
有许多表达式通常都是产生列表的。当其在标量context 中使用时,会得到什么结果呢?让我们看看这个操作的创始人怎么
解释的。通常,这个人是Larry,其文档展现了整个历史。对于Perl 的学习,大部分是学习Larry 是怎么的想的◆。因此,
一旦你能像Larry 那样思考时,你就能明白Perl 的行为。当学习时,你可能需要查看其文档。
◆更准确的说,Larry 创建Perl 时,是按照你希望它怎样操作来设计的。
Perl 语言入门(第四版)
49 / 201 9/21/2006
一些表达式根本没有标量context 的值。例如,sort 在标量context 中返回什么?你不需要要排序一个列表来得到其个数,因
此,除非有人按另一种方式实现了sort,否则其在标量context 中返回undef。
另一个例子是reverse。在列表context 中,它返回反转的列表。在标量context 中,返回反转的字符串(或者将反转的结果串
成一个字符串):
@backwards = reverse qw / yabba dabba doo /;
#返回doo, dabba, yabba
$backwards = reverse qw/ yabba dabba doo /;
#返回oodabbadabbay
开始时,你可能对于表达式是在标量或者列表context 中使用不太清楚。但,你将很快习惯它。
下面是一些例子:
$fred = something; # 标量context
@pebbles = something; #列表context
($wilma,$betty) = something; #列表context
($dino) = something; #列表context
不要被只有一个元素的列表所欺骗;最后一个是列表context 而非标量context。括号是必须的,它使第四个区别于第一个。
如果将其赋给列表(和元素个数无关),则为列表context。如果赋给数组,也是列表context。
让我们看看已经出现过的一些别的表达式及其context。下面是一些标量context:
$fred = something;
$fred[3] = something;
123 + something;
something + 654
if(something){… }
$fred[something] = something;
下面是一些列表context:
@fred = something;
($fred, $barney) = something;
($fred) = something;
push @fred, something;
foreach $fred(something)
sort something
reverse something
print something
Perl 语言入门(第四版)
50 / 201 9/21/2006
3.7.2 在列表Context 中使用Scalar-Producing 表达式
其用法是显然的:如果一个表达式不是列表值,则标量值自动转换为一个元素的列表:
@fred = 6*7;
@barney = “hello”. ‘’. “world”;
下面是另一个例子:
@wilma = undef; #OOPS!得到一个元素的列表(undef),不同于下面的例子
@betty = (); #将数组置空的正确方法
由于undef 是一个标量值,将undef 赋给数组不会清空数组。一个更好的方法是将空列表赋给它◆。
◆在现实中,如果变量被合适的定义在恰当的作用域(scope)中,则不需要明确的将其清空。这种赋值语句在优秀的Perl 程序中很少出现。
在下一章将学习作用域。
3.7.3 强制转换为标量Context
偶尔,你可能需要标量context 而Perl 期望的是列表。这种情况下,可以使用函数scalar。它不是一个真实的函数因为其仅
是告诉Perl 提供一个标量context:
@rocks = qw(talc quartz jade obsidian);
print “How many rocks do you have?\n”;
print “I have ”, @rocks, “rocks!\n”; #错误,输出rocks 的名字
print “I have ”, scalar @rocks, “rocks!\n”; #正确,输出其数字
奇怪的是,没有对应的函数能强制转换为列表context。但请相信我们,事实上你并不需要它。
3.8在列表Context 中
前面学习过行输入操作:,在不同的上下文环境中返回不同的值。像早先描述的那样在标量context 中返
回输入的下一行。在列表context 中,它将返回这个输入文件的所有剩余部分。而每一行将作为一个独立的元素,如下所示:
@lines = ; #将输入读入列表context 中
当输入来源于一个文件时,它将读入文件的剩余部分。但如果输入来源于键盘,那文件结束符(end-of-file)是怎样输入的呢?
在Unix 或者类似的系统中,包括linux, Mac OS X,通常可以输入CTRL +D◆来表明输入已经结束。Perl 会忽略这个字符,
因此它将在屏幕上显示出来。在DOS/WINDOWS 系统中,使用CTRL +Z◆。如果你的实际情况和上述不同,查看你系统
的文档或者询问你附近的专家。
Perl 语言入门(第四版)
51 / 201 9/21/2006
◆这仅仅是默认值,可以使用stty 来改变它。但通常是使用它;我们还没有看见某台Unix 系统不是使用CTRL+D 来表明end-of-file 的。
◆在Perl 的某些DOS/WINDOWS 版本中可能存在bug,在第一行中使入CTRL+Z 可能存在问题。在这样的系统中,可以使用在输入的结
束处加上“\n”来解决。
如果某人运行一个程序,输入了三行,并且使用了恰当的end-of-file,那其数组将含有3 个元素。每一个元素为一个由换行
符结束的字符串,对应于由3 个换行符结束的输入。
如果在输入时,能一次去掉(chomp)所有的换行符,岂不是很好?如果将chomp 应用于一个包含字符串的数组中,他将把这
个数组中每一个元素的换行符去掉,如下例所示:
@lines = ; #读入所有的行
chomp = (@lines); #去掉所有的换行符
但更常见的做法是:
chomp (@lines = ); #读入所有的行,不包括换行符
当写你自己的程序时,可以采用任意种方法,大多数Perl 程序员使用第二种,更加紧凑些。
你可能已经意识到这些输入一旦读过,就不能重新读了◆。到了文件的结尾,就没有更多的数据可以读入。
◆如果是从某个源(source,如文件,译者注)输入,那你可以返回去重新读一次。但这不是这里讨论的问题。
当输入的文件为一个400MB 的log 文件时,将发生怎样的情况?行输入操作符读入所有的行,这将占去大量的内存◆。Perl
不会限制你那样做,但你系统的用户(更别提系统管理员)将很可能阻止你。当输入的内容特别大时,应当避免一次将所
有的内容都读入内存。
◆一般,实际占去的内存要比文件要大。也就是说,一个400MB 的文件读入数组时将至少占去1G 的内存空间。这是因为Perl 为了节约时
间而浪费了些内存。这是一个好的交易。如果内存不够,可以去买一些;但时间不够,那就很难办了。
3.9 练习
1. [6] 写一个程序,将一些字符串(不同的行)读入一个列表中,逆向输出它。如果是从键盘输入的,那在Unix 系统中
应当使用CTRL+D 表明end-of-file,在Windows 系统中使用CTRL+Z.
2. [12] 写一个程序,读入一串数字(一个数字一行),将和这些数字对应的人名(下面列出的)输出来。(将下面的人
名列表写入代码中)。例如,当输入为1,2,4 和2,则输出的为fred, betty, dino, 和betty:
fred betty barney dino Wilma pebbles bamm-bamm
3. [8]写一个程序,将一些字符串(在不同的行中)读入一个列表中。然后按ASCII 顺序将它们输出来。也就是说,当输
Perl 语言入门(第四版)
52 / 201 9/21/2006
入的字符串为fred, barney, wilma, betty,则输出为barney betty fred wilma。分别在一行或不同的行将之输出。
Perl 语言入门(第四版)
53 / 201 9/21/2006
第四章子程序
你已经见过一些内嵌的函数了,如chomp, reverse, 和print。但,如其它某些语言一样,Perl 也可以构造子程序(subroutines),
它们是用户定义的◆。这可以让我们在程序中重复使用某段代码◆。子程序的名字是Perl 中的另一个标识符(由数字,字符,
下划线但不能由数字开头的串组成),有时由可选的符号(&)开头。关于何时需要,何时不需要&的规则,在本章的结尾处将
介绍。现在,如果允许时我们都将使用它(&),这通常是一种安全的做法。当然,在禁止使用时我们会提醒你。
◆在Perl 中,我们不像Pascal 程序那样严格的区分:函数(functions),将返回值;和子程序(procedures),不返回值。子程序(subroutine)总
是用户定义的,而函数(function)可能不是。也就是说,某个函数可能是子程序(subroutine),或者是Perl 内嵌的函数(funcitions)。这也就
是我们把本章叫做Subroutines 的原因:因为是关于你自定义的而非系统内嵌的函数。
◆本书中40%的代码来源于公开的商用程序,如果合理使用,75%的代码都可以在你的程序得到重用。
子程序的名字属于一个独立的名字空间,因此Perl 不会在你的子程序为&fred 同时也有一个变量为$fred 的情况下混淆,当
然通常是没有理由这样命名的。
4.1 定义一个子程序
要定义自己的子程序,使用关键字sub,子程序的名字(无&这个符号),组成子程序的缩进的代码块(花括号中),如:
◆恰当的说,花括号也属于块的一部分。Perl 不需要缩进块中的代码,但维护人员需要。因此请遵守这个规则。
sub marine {
$n + = 1; #全局变量$n
print “Hello, sailor number $n!\n”;
}
子程序(本章中若无特殊说明,子程序均指subroutine,译者注)的定义可以在程序的任意位置,但具有如C 或者Pascal 背景
的程序员通常将它们放在程序的开头。某些其它的程序员可能将它们放在结尾,以使程序的主要部分在开头出现。不需要
在定义之前有任何声明。子程序的定义是全局的;没有某些强大的技巧,Perl 中没有私有子程序(private subroutines)◆。如
果两个子程序有相同的名字,那后一个将覆盖前一个◆。这被看作是一种不好的编成习惯,它将迷惑你的维护人员。
◆如果想使用特殊的技巧,阅读Perl 的关于私有变量(private variables)中的coderefs 文档。
◆将会引起警告
如前面例子那样,可以在子程序中使用全局变量。事实上,到现在为止所出现的所有变量均是全局的;也就是说,它们在
程序的任意部分都可以被访问。这让纯粹的语言学家感到恐慌,但一些Perl 的开发者却大量使用它们。在本章后面的“子
Perl 语言入门(第四版)
54 / 201 9/21/2006
程序的私有变量”一节中将介绍怎样创建私有变量。
4.2 调用子程序
可以使用子程序的名字(带有&)来调用子程序◆:
◆通常有括号,即便参数为空。子程序将继承调用者的@_的值,这会马上讨论。因此不要在这里停止,否则程序可能和你预期的行为不同。
&marine; #输出Hello, sailor number 1!
&marine; #输出Hello, sailor number 2!
&marine; #输出Hello, sailor number 3!
&marine; #输出Hello, sailor number 4!
通常,我们说调用(invocation)是指调用子程序(call the subroutine)。
4.3 返回值
子程序可以被某个表达式调用,无论此表达式的值是否被利用。如早些的例子&marine,我们得到此表达式的值,但其值被
扔掉了。
许多时候,当调用某个子程序时,需要使用其返回值。这意味着应当注意子程序返回值。所有的Perl 子程序都会返回值,
在Perl 中返回值和不返回值是没有区别的。当然,不是所有Perl 子程序返回的值都是有用的。
由于所有的被调用的子程序都要返回值,因此使用特殊的返回值语法在大多数情况下是一种浪费。因此Larry 将之简化了。
当Perl 遍历此子程序时,将会计算每一步的值。此子程序中最后计算的值将被返回。
例如,下面的子程序:
sub sum_of_fred_and_barney{
print “Hey, you called the sum_of_fred_and_barney suroutine!\n”;
$fred + $barney; #返回值
}
子程序中最后一个被计算的表达式为$fred + $barney,因此$fred 和$barney 的和将被返回。下面是一些调用代码:
$fred = 3;
$barney = 4;
$wilma = $sum_of_fred_and_barney; #$wilma 得到7
print “\$wilma is $wilma.\n”;
$betty = 3 * &sum_of_fred_and_barney; #$betty 得到21
print “\n$betty is $betty.\n”;
Perl 语言入门(第四版)
55 / 201 9/21/2006
上述代码将得到下面的输出:
Hey, you call the sum_of_fred_and_barney subroutine!
$wilma is 7.
Hey, you call the sum_of_fred_and_barney subroutine!
$betty is 21.
上述print 语句是用于调试的,从它可以看到子程序被调用了。当程序调试好后,应当把它们去掉。假设在上述子程序中加
入了下面的一行代码:
sub sum_of_fred_and_barney{
print “Hey, you called the sum_of_fred_and_barney subroutine!\n”;
$fred + $barney; #其值不会被返回
print“Hey, I’m returning a value now!\n”; #oops!
}
在上述例子中,最后一个被计算的表达式不是$fred + $barney;而是print 语句。其返回值通常为1,意思是“print was
succfessful(打印成功)”◆;但这不是你想要的返回值。因此当向子程序加入新的代码时要小心些,因为返回值为最后一
个被计算的表达式。
◆当print 成功时返回true,失败时返回false。下一章将了解到更多种类的失败。
因此,第二个子程序中$fred + barney 的值去哪里了呢?由于没有把它存放在任何地方,Perl 将它丢弃了。如果打开了警告,
Perl(注意到两个变量相加但其值未被使用)可能给出如下的警告信息“a useless use of addition in a void context.” 术语void
context 是说其值未被存于变量或者被别的方式使用。
“The last expression evaluated”的含义是指最后一个被求值的表达式,而非程序的最后一行。例如,下面的子程序返回$fred
和$barney 的较大值:
sub larger_of_fred_or_barney {
if ($fred > $barney){
$fred;
}else{
$barney;
}
}
最后一个被求值的表达式是$fred 或者$barney,因此其中的某个变量成为返回值。在代码实际运行前,不知道是$fred 或
$barney 的值将被返回。
上述例子没有什么价值。如果每次调用子程序时可以传递不同的参数比依靠全局变量要好许多。这将在下面进行介绍。
Perl 语言入门(第四版)
56 / 201 9/21/2006
4.4 参数(Arguments)
如果子程序larger_of_fred_barney 不是必须使用全局变量$fred 和$barney,那将变得更有用。如果要得到$wilma 和$betty 中
较大的值,现在必须将将它们的值拷贝到$fred 和$barney 中,然后再调用large_of_fred_or_barney。如果不希望改变这些变
量的值,那首先必须把这些变量拷贝到其它变量之中,如$save_fred 和$save_barney。然后,当子程序结束时,再把它们拷
贝回变量$fred 和$barney。
幸运的是,Perl 子程序可以带参数。将参数列表传给子程序中的方法是,在程序名后面接括号,括号内存放参数列表,如:
$n = &max(10,15); #此子程序有2 个参数
此参数列表被传到子程序中;这些参数可以被子程序使用。当然,这些参存放在某个地方,在Perl 中,会自动将此参数列
表(此参数列表的另一个名字)自动存放在一个叫做@_的数组中。子程序可以访问次数组变量来确定此参数的个数以及
其值。
这也就是说此子程序参数的第一个值存放在$_[0]中,第二个存放在$_[1],依次类推。但必须强调的是这些变量和$_这个
变量没有任何关系,如$dino[3](数组@dino 的一个元素)和$dino 的关系一样。这些参数必须存放在某个数组变量中,而Perl
存放在@_这个变量中。
现在,可以写子程序$max,其功能类似于&larger_of_fred_or_barney,但不是使用$fred,而使用($_[0]);不使用$barney,
而使用($_[1])。因此可以如下这些写代码:
sub max{
#和&larger_of_fred_or_barney 比较
If($_[0] > $_[1]){
$_[0];
}else{
$_[1];
}
}
我们说,你可以这样做。但使用这些下标有些难看,并且难于阅读,书写,检查,调试等。后面有更好的方法。
这个子程序有另一个问题。&max 这个名字很简单,但当调用的参数不是两个时,此程序不能提示出了错误:
$n = &max(10,15,27); #oops!
额外的参数被忽略了;因为此子程序不会使用$_[2],Perl 不会关心是否有多余的变量。参数不够时也会被忽略,当传入的
参数个数不够时,不够的参数会得到undef 这个值。在本章后面,将会有更好的方法,它可以在参数个数任意的情况下正
常工作。
@_是子程序的一个私有变量◆;如果有一个全局变量@_,它将在此子程序调用前存储起来,当子程序调用完成后,其早
期的值会被重新赋还给@_◆。这意味着当将参数传递给子程序时不用担心它会影响此程序中其它子程序的@_这个变量的
Perl 语言入门(第四版)
57 / 201 9/21/2006
值。嵌套的子程序调用时,@_的值和上述类似。甚至此子程序递归调用时,每一次调用将得到新的@_,因此子程序调用
时将得到其自身的参数列表。
◆除非调用的子程序前有&而后面没有括号(或者没有参数),此时@_从此调用者的上下文(context)得到。这通常不是个好主意,但有时很
有用。
◆你可能意识到这里使用的机制和上一章中foreach 循环是一样的。在每种情况下,变量值被Perl 自动保存和重新赋值。
4.5 子程序中的私有变量
Perl 在每一次调用时提供@_这个私有变量,那它可以给我们提供私有变量吗?答案是,能。
默认情况下,Perl 中所有变量都是全局的;也就是说,这些变量可以在程序的任意部分使用。你也可以任意时候使用my
创建私有变量:
sub max {
my($m,$n); #新的,私有变量
($m,$n) = @_; #赋值
if($m > $n) {$m} else{$n}
}
这些变量是此代码块中的私有的(或者局部的)变量;别的$m 和$n 不会影响此处的两个变量。而且,其它地方的代码不
能访问或者修改这些变量◆。你可以将此子程序放在任意地方而不用担心它们会和程序其它地方的$m,$n(如果有)变量
混淆◆。在if 代码块内部,其语句没有分号。Perl 允许省略括号中最后一条语句的分号,在实际代码中,通常仅当此代码
块仅包含一条语句时才省略此分号。
◆高级的程序员知道在程序外部可以通过引用而非变量名字来访问私有变量。
◆当然,如果此程序中还有一个叫做$max 的子程序,那将引起混淆。
前一例中的子程序可以变得更简单。你注意到列表($m,$n)书写了2 次吗?my 操作符可以用在有括号的变量的列表中,因
此,通常将上述两个语句如下书写:
my($m,$n) = @_;
上面的一条语句创建了一些私有变量并给它们赋值,第一个为$m,第二个为$n。几乎每一个子程序都由类似的语句开头。
当看见那一行时,你就知道此子程序需要2 个变量,在此子程序中非别被叫做$m 和$n。
4.6 参数列表的长度
在实际的Perl 代码中,传递给子程序的参数个数是没有限制的。这符合Perl 的设计哲学“没有不必要的限制”。当然,有
Perl 语言入门(第四版)
58 / 201 9/21/2006
一点和传统的程序设计语言很不相同,这些语言中要求其子程序中参数个数和参数类型是严格确定的。Perl 的这种灵活特
性很好,但(你将在&max 这个函数中看到)可能引起问题,如使用了错误的参数个数来调用子程序。
当然,子程序可以容易的检测@_是否含有恰当的个数。例如,我们可以如下的书写&max◆:
◆当在下一章学习warn 后,你可以使用恰当的警告信息。如果认为这是个严重的问题,也可以使用die,这也将在同一章中有介绍。
sub max{
if(@_!=2){
print “WARNING! &max should get exactly two arguments!\n”;
}
#continue as before….
.
.
.
}
if 语句检测参数个数是否恰当(此时,数组是在标量环境中使用的,它将返回其个数),在第三章中有介绍。
但在实际的Perl 程序中,很少使用这样的方法;更好的方法是子程序可以在任意参数个数的调用者中正常工作。
4.6.1 更好的&max 程序
现在重写&max,使它可以在任意参数个数下都能正常工作:
$maximum = &max(3,5,10,4,6);
sub max {
my($max_so_far) = shift @_;
foreach (@_){
if($_>$max_so_far){
$max_so_far=$_;
}
}
$max_so_far;
}
这段代码使用了一种叫做high-water mark 的算法:洪水之后,会在岸边留下痕迹。最高处的标记,表明了到达的最高水位。
在此程序中,$max_so_far 记录最高的水位。第一行中置$max_so_far 为3(第一个参数),它是从参数数组:@_中移出来的。
此时,@_变成了(5,10,4,6),因为3 已被移出。此时出现过的最大数为3。
现在,foreach 循环遍历@_剩下的值。循环中的控制变量是默认变量$_。(请记住,$_和@_没有任何关系;它们名字相同
Perl 语言入门(第四版)
59 / 201 9/21/2006
完全是巧合)。第一次循环时,$_为5。if 测试语句中发现它比$max_so_far 大,因此$max_so_far 现在变成了5。
下一次循环中,$_为10。它是一个更大的值,此时$max_so_far 为10。
接着,$_为4。现在$_小于$max_so_far:10。因此,if 中的语句块被跳过。
接着,$_为6,基于同样的原因,if 语句块被跳过。这是最后一次循环。
现在,$max_so_far 的值将被返回。他为最大值:10。
4.6.2 空参数列表
经过改进后的&max 有了很大的提高,其参数可以不是2 个。但,如果参数个数为0,会发生什么情况呢?
初次遇到这个问题时,可能认为其过于深奥。毕竟,谁会调用&max 而不给其参数呢?但是,某人可能如下书写:
$maximum = &max(@numbers);
而@numbers 可能为空,例如可能从空文件读入。因此,你需要知道,&max 此时会怎样处理呢?
子程序第一行将@_的第一个元素赋给$max_so_far。这不会有什么坏影响;数组为空,shift 操作返回undef 给$max_so_far。
现在进入foreach 循环体,由于为空,循环体一次都不执行。
现在,Perl 返回$max_so_far 的值undef。在某种意义下,这是正确的答案,因为空表中没有最大的元素。
当然,当调用此子程序时注意返回值可能为undef,或者保证调用的参数非空。
4.7my 变量的注释
这些局部变量可以在任意块中使用,不仅仅是子程序中。例如,可以在if,while,foreach 等块中使用:
foreach (1..10){
my($square) = $_*$_; #本循环中的私有变量
print “$_ squared is $squrare.\n”;
}
变量$square 是私有的,仅在此块中可见;在本例中,此块为foreach 循环块。如果没有大括符({}),它将是整个文件中的
私有变量。到现在为止,你的程序不会超过一个文件,因此不讨论这个问题。只有和它处于一个代码块中的语句才能使用
它。这非常有利于代码的维护,如果$square 值错了,则其被限制在相应的代码段中。有经验的程序员(通常是通过辛苦的
实践)发现将变量的作用域限制在一页,或者几行代码中,能加速开发和测试。
Perl 语言入门(第四版)
60 / 201 9/21/2006
当然,my 操作不会改变赋值参数的context:
my ($num) = @_; #列表context, 同($sum) = @_;
my $num = @_; #标量context,同$num = @_;
在第一个例子中,$num 得到第一个参数,因为其在列表context 中;第二个例子中,将得到参数的个数,因为是在标量context
中。两条语句都可能是正确的;不能仅凭它来判断是否使用错误,因此Perl 不能提示(warning)你,如果你使用错误。(当
然,不能将这两天语句写在同一个子程序中,因为不能在一个作用域内重复定义某个变量)。当读到这样的代码时,可以通
过上下文来判断其context。
记住,如果没有使用括号,my 仅定义一个变量◆:
◆通常,将warning 打开会报告这样使用my,或者你自己调用1-800-LEXICAL-ABUSE 来报告。使用strict pragma(将在后面提及),将会
阻止这类错误的发生。
my $fred, $barney; #错误!没有定义$barney
my ($fred, $barney); #两个均定义了
当然,可以使用my 创建新的,私有数组◆:
◆或者hashes,在第六章中有介绍
my @phone_number;
如果新的变量没被赋值的话:标量变量会自动赋与undef,而数组变量会赋与空列表。
4.8 使用strict Pragma
Perl 是一种宽容的语言◆。你可能希望Perl 严格一些;那可以使用strict pragma。
◆你可能还没注意到。
pragma 可以提示编译器,告诉它一些关于这块代码的信息。如,使用strict pragma 告诉Perl 的编译器,应当严格的检查这段代码。
为什么要使用这种方法呢?假设你写一个程序,输入了如下这一行:
$bamm_bamm = 3; #Perl 自动创建这个变量
现在,你接着输入一些新的代码。当上面一条语句滚动到屏幕以外时,你输入了下面这条语句:
$bammbamm + =1; #Oops!
Perl 语言入门(第四版)
61 / 201 9/21/2006
由于Perl 把它当作一个新的变量(下划线是有含义的),它将创建这个变量,并增1。如果你足够幸运或者聪明,打开了警
告(warnings),Perl 将告诉你这个,或者这两个变量仅使用了一次。如果你没那么幸运,每个变量使用了不止一次,那Perl
将不会警告你。
告诉Perl 进行更严格的语法检测,需要在程序顶端use strict(或者在任意块或者文件中,如果你需要在此部分使用它):
use strict; #迫使采用更严格的检测
现在,除了其它限制外◆,Perl 将要求你在申明每一个新的变量时,使用my◆:
◆要想知道更多的限制,可以查看关于strict 的文档。文档是按照pragma 的名字来归档的。因此,命令perldoc strict(或者你系统中查看文
档的命令)将为你找到相应的文档。
◆当然,还有一些别的声明变量的方法。
my $bamm_bamm=3 ; #新的局部变量
如果,你把它拼写成别的形式,Perl 将警告你,你没有定义如$bammbamm 的变量,因此这类错误在编译时既能发现。
$bammbamm+=1; #没有这样的变量;编译时错误
当然,这只是针对Perl 的新的变量;对于Perl 内嵌的变量如,$_,@_则不需要申明◆。如果在以前的程序中使用use strict,
那很可能得到许多警告信息,因此你应当养成使用strict 的习惯。
◆在某些情况下,不应当申明$a, $b,因为它们被sort 使用。因此,遇到这种问题时,使用其它的变量名。事实上,use strict 不会阻止这两
个变量,在Perl 中不算bugs。
许多人推荐如果程序长度大于一个屏幕,则需要使用use strict。我们赞成这种观点。
从现在开始,我们例子中的大多数程序(不是全部)将使用use strict,虽然有时我们没有将它明显的写出。因此,当定义
新变量时,我们将使用my。虽然,我们不经常这样做,但是我们推荐你在你的程序中尽可能的使用use strict。
4.9 返回操作
返回操作将立刻的从子程序中返回一个值:
= qw /fred barney betty dinoWilma pebbles bam-bamm/;
my $result = &which_element_is(“dino”, @names);
sub which_element_is{
my($what, @array) = @_;
foreach(0..$#array){ 元素的索引
if($waht eq $array[$_]){
Perl 语言入门(第四版)
62 / 201 9/21/2006
return $_; #找到既返回
}
}
-1; #没有找到元素(此处是可选的)
}
这个子程序是寻找@names 中“dino”的索引值。首先,定义了2 个参数:$what, 查找的对象;@array,被搜索的数组。本
例中为@names 的一份拷贝。foreach 循环遍历数组@array(第一个索引值为0,最后一个为$#array,第三章中有介绍)。
每一次循环时,将检测数组@array 当前的元素的是否为$what 中的元素◆。如果相同,则返回此时的索引值。从当前代码
返回的最常用方法是使用return 语句,它将立刻返回,而不会执行其余的代码。
◆注意此时的比较符为,eq,而非= =。
如果不存在所要查找的元素呢?在本例中,子程序返回-1,表明“值不存在”。如果想更加Perlish,那可以返回undef,但
本例中,程序员选择了-1。上例中使用return -1 也是正确的,但return 是多余的。
某些程序员喜欢每次都使用return 语句,表明其为返回值。例如,你可能想从子程序中立刻返回(非最后一行)而使用return,
如本章前面的&larger_of_fred_or_barney 这个例子。这并非是必须的,但也没什么坏的影响。对大多数Perl 程序员来讲,这
仅是多输入七个字母而已。
4.9.1 省略符号&
有几条规则确定在调用子程序时是否可以省略掉&。如果编译器在调用之前知道此子程序的定义,或者Perl 从语法中能知
道这是一个子程序调用,则子程序前的符号&是可以省略的,像使用内嵌(built-in)函数一样(这些规则后有一个特例,将在
下面了解到)。
这意味着如果Perl 能通过语法就能判断其是否为子程序调用,那将非常方便。例如,如果用括号将一些参数括起来,那其
为函数◆调用:
◆在下例中,其调用的子程序为&shuffle。但它可能是一个内嵌的函数。
my @cards = shuffle(@deck_of_cards); # &是不必要的
如果Perl 内部的编译器知道此子程序的定义,则可以省掉其参数的括号:
sub division{
$_[0] / $_[1]; #第一个参数除以第二个参数
}
my $quotient = division 355, 113; #可以省略掉括号
上述代码能正常运行,因为如果加上括号不能改变其含义,那括号就是可选的。
Perl 语言入门(第四版)
63 / 201 9/21/2006
但不要将上述子程序的声明放在调用函数的后面,否则编译器不知道调用division 是什么意思。编译器需在调用前知道其
定义,那样就可以将它当作内嵌(built-in)的函数看待了。
上述并非其特别的地方。特别的地方为:如果子程序和Perl 一个内嵌程序同名,则必须使用&来调用它。编译器将在调用
之前检查其定义,而非直接将它当作内嵌的函数来处理。加上&,可以确保你调用了此子程序;不加,则仅当没有同名的内
嵌函数时才能调用到它:
sub chomp {
print “Munch, Munch!\n”;
}
&chomp; #此处的&是必须的
如果没有&,我们将调用内嵌的函数chomp,虽然已经定义了子程序&chomp。因此,实际的使用规则是:除非知道Perl 所
有的内嵌函数,否则函数调用时都应当使用&。这即是说在你头几百个程序都应当使用&。但如果你看到某人的代码中省略
掉了&,这并非一定是错误;可能他们知道Perl 没有具有相同名字的内嵌函数◆。当程序员打算调用其自己的子程序和调
用内嵌的(built-in)函数一样时,通常是写模块(modules),经常使用原形(prototypes)来告诉Perl 预期的参数类型。创
建模块是一种高级技术;当你准备好时,可以参看Perl 的关于子程序原型(subtoutine prototypes)和创建模块(making modules)
的文档(特别是perlmod 和perlsub 两份文档)。
◆当然,他们也可能犯错误;你可以搜索perlfunc 和perlop 的用户手册来查看其是否为某个内嵌函数的名字。当把警告(warnings)打开时,
Perl 会提示你这种问题。
4.10 非标量返回值
标量并非子程序返回的唯一类型。如果你在列表context 中调用某个子程序◆,则其会返回列表值。
◆你可以使用wantarray 函数来判断一个子程序是在标量还是列表context 中使用的,这可以让你轻松的写出恰当的子程序。
假定想得到某个范围内的数字(如范围操作符),从小到大,或者从大到小。范围操作符只能从小到大,但可以很容易的弥
补这种缺陷:
sub list_from_fred_to_barney {
if($fred < $barney) {
#Count upwards from $fred to $barney
$fred ..$banrey
} else {
#Count downwards from $fred to $barney
reverse $barney ..$fred;
}
$fred = 11;
$barney = 6;
@c = &list_from_fred_to_barney; 为(11,10,9,8,7,6)
Perl 语言入门(第四版)
64 / 201 9/21/2006
在本例中,范围操作符给我们6 到11 的列表,reverse 倒转此列表,因此得到从11 到6 的列表。
也可以什么都不返回。如果return 后没有任何参数则在标量context 中将返回undef,而在列表context 中将返回空列表。这
有助于检验子程序是否返回了正确信息,提示调用者当前不能返回更有意义的值。
4.11 练习
附录A 中有答案:
1.[12]写一个名为&total 的子程序,返回一列数字的和。提示:子程序不应当有任何的I/O 操作;它处理调用的参数,返
回处理后的值给调用者。结合下面的程序来练习,它检测此子程序是否正常工作。第一组数组之和我25。
my @fred = qw{ 1 3 5 7 9 };
my $fred_total = &total(@fred);
print "The total of \@fred is $fred_total.\n";
print "Enter some numbers on separate lines: ";
my $user_total = &total();
print "The total of those numbers is $user_total.\n";
2.[5]利用上题的子程序,写一个程序计算从1 到1000 的数字的和
3.[18]额外的练习:写一个子程序,名为&above_average,将一列数字作为其参数,返回所有大于平均值的数字(提示:
另外写一个子程序来计算平均值,总和除以数字的个数)。利用下面的程序进行测试:
my @fred = &above_average(1..10);
print "\@fred is @fred\n";
print "(Should be 6 7 8 9 10)\n";
my @barney = &above_average(100, 1..10);
print "\@barney is @barney\n";
print "(Should be just 100)\n";
Perl 语言入门(第四版)
65 / 201 9/21/2006
第五章输入与输出
我们在早期练习中已经使用过一些输入/输出(I/O)操作。现在我们将学习更多的此类操作,其涵盖了大概80%的输入/输出内
容。如果熟悉标准输入,输出,错误流,将更有利于本章的学习。如果不熟悉,通过本章的学习你将掌握这类知识。现在,
想象“标准输入(standard input)”为“键盘”,“标准输出(standard output)”为“显示器”。
5.1 从标准输入设备输入
从标准输入设备输入是容易的。使用,我们已经见过了◆。在标量context 中它将返回输入的下一行:
◆这里,我们称:为行输入操作,但其实际上是对一个文件句柄(filehandle)的行输入操作(有<>表示)。本章后面将更多的介绍文
件句柄(filehandle)。
$line = ; #读入下一行;
chomp($line); #去掉结尾的换行符
chomp($line=) #同上,更常用的方法
由于,行输入操作在到达文件的结尾时将返回undef,这对于从循环退出时非常方便的:
while (defined($line = )) {
print “I saw $line”;
}
第一行代码值得仔细说明:我们将输入的字符串读入一个变量,检查其是否defined,如果是(意味着我们没有到达输入的
结尾),则执行while 的循环体。因此,在循环的内部,我们将看到每一行,一行接着一行◆。你可能经常进行此类操作,
因此Perl 提供了一种简写方式。如下:
◆你可能注意到我们没有对输入的字符串进行chomp 操作。在这种类型的循环中,你不能将chomp 操作插入条件表达式中,因此这通常是循
环体的第一条语句。我们将在下一节中见到此类例子。
while(){
print “I saw $_”;
}
为了得到这种简写,Larry 使用了一些无用的语法(useless syntax)。也就是说: “读入一行输入,看其是否为真(通常为真)。
如果为真,则进入while 循环,然后丢掉它!”。Larry 知道很少有人这样做;没人会在实际的程序中使用这种方法。因此,
Larry 利用了这种特性,使之变得有用起来。
Perl 语言入门(第四版)
66 / 201 9/21/2006
上段程序实际完成的工作和早期例子是一样的:它告诉Perl 将输入读入一个变量,(只要结果是defined 的,即没有到达文
件的结尾),则进入while 循环。但,不是将输入存储在$line,而是放在Perl 的默认变量,$_之中。你也可以这样写:
while (defined($_ = )){
print “I saw $_”;
}
在进行深入讨论前,我们要澄清一些事:这种简写只在特定的情况下有效,默认的情况下不会将一行读入变量$_。仅当while
循环的条件判断部分只包含行输入操作才有效◆。如果在条件判断部分还有别的内容,则上述简写无效。
◆由于for 循环的条件部分和while 的条件部分类似,它也能正常工作。
除此之外,行输入操作()和Perl 的默认变量($_)没有别的关系。在本例中,输入的值被保存在变量$_中。
另一方面,在列表context 中使用行输入操作时,则会将所有的行(剩下的)当作一个列表,而每一行作为列表的一个元素:
foreach(){
print “I saw $_”;
}
同样,行输入操作和Perl 的默认变量$_没有必然的联系。在上例中,foreach 默认的控制变量为$_。因此,此循环将每一行
赋给$_。
上面的看起来相似:好像有理由认为它们的行为也是相似的,不是吗?
它们在底层是很不相同的。在while 循环中,Perl 读入一行,将它赋给变%
阅读(1313) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~