perl教程009

perl教程009 - 下载...

Info iconThis preview shows page 1. Sign up to view the full content.

View Full Document Right Arrow Icon
This is the end of the preview. Sign up to access the rest of the document.

Unformatted text preview: 下载 第二部分 高级特性 第 9学时 第 10 学时 第 11学时 第 12学时 第 13学时 第 14 学时 第 15学时 第 16 学时 其他函数和运算符 文件与目录 系统之间的互操作性 使用 Perl 的命令行工具 引用与结构 使用模块 了解程序的运行性能 Perl 语言开发界 下载 第 9学时 其他函数和运算符 P e r l遵循的传统原则是“一件事情可以使用许多方法来完成” 。在本学时中,我们将要更 加深入地掌握这个原则。我们将要学习丰富多彩的新函数和运算符。 为了进行标量搜索和操作,到现在为止我们一直使用正则表达式。不过我们可以使用多 种方法来完成这项任务, Perl 提供了各种各样的函数,以便对标量进行搜索和编辑。在本学时 中,我们将要介绍其他的几种方法。 另外,我们介绍了作为项目的线性列表的数组,你可以使用 foreach迭代通过这些列表,或 者使用 join将它们组合起来,构成标量。在本学时中,我们将要介绍一种观察数组的全新方法。 最后,我们要重新介绍一下常用的 p r i n t 函数,并且给它增加一点特性。使用新的改进后 的print 函数,你就能够编写格式优美、适合向他人展示的报表。 在本学时中,你将要学习: • 如何对标量进行简单的字符串搜索。 • 如何进行字符替换。 • 如何使用 print函数。 • 如何将数组用作堆栈和队列。 9.1 搜索标量 正则表达式非常适合对标量进行搜索,以便找出你要的模式,但是有时使用正则表达式 来搜索标量有点像杀鸡用牛刀的味道。在 perl中,对模式进行组装,然后在标量中搜索该模式, 需要花费一定的开销,不过这个开销并不大。另外,当你编写正则表达式时,很容易出错。 为此, perl提供了若干个函数,用于对标量进行搜索,或者从标量中取出简单的信息。 9.1.1 用index进行搜索 如果你只想在另一个标量中搜索单个字符串,Pert提供了index函数。index函数的句法如下: i n d e x函数从 s t r i n g的左边开始运行,并搜索 s u b s t r i n g。i n d e x返回找到 s u b s t r i n g 时所在的位 置, o是指最左边的字符。如果没有找到 s u b s t r i n g,i n d e x便返回 - 1 。被搜索的字符串可以是字 符串直接量,可以是标量,也可以是能够返回字符串值的任何表达式。 s u b s t r i n g 不是一个正 则表达式,它只是另一个标量。 请记住,你编写的 Pert函数和运算符可以带有包含参数的括号,也可以不带。下面是一些 例子: 104 使用第二部分 高 级 特 性 下载 根据情况,可以给 i n d e x 函数规定一个字符串中开始进行搜索的起始位置,如下面的例子 显示的那样。若要从左边开始搜索,使用的起始位置是 0: 也可以使用带有起始位置的 i n d e x 函数,以便“遍历”一个字符串,找到出现一个较短字 符串的所有位置,如下所示: 上面这个代码滑动通过$ source,如下所示: 9.1.2 用rindex向后搜索 函数 rindex的作用与 index基本相同,不过它是从右向左进行搜索。它的句法如下所示: 当搜索到结尾时, rindex返回 -1。下面是一些例子: 用于index的遍历循环与使用 rindex进行向后搜索的循环略有不同。 rindex的起点必须从字符 的结尾开始,或者从结尾的后面开始, (在下例中,从length($source)开始) ,但是,当返回-1时, 它仍然应该结束运行。当找到每个字符串后,$ start必须递减1,而不是像index那样递增1。 9.1.3 用substr分割标量 s u b s t r是个常常被忽略和很容易被遗忘的函数,不过它提供了一种从标量中取出信息并对 标量进行编辑的通用方法。 substr 的句法如下: 下载 105 第9学时 其他函数和运算符使用 substr函数取出 string,从位置o ff s e t开始运行并返回从 o ff s e t到结尾的字符串的剩余部分。 如果设定了 length,那么取出 length指明的字符,或者直到找出字符串的结尾,以先到者为准, 如下例所示: 如果 o ff s e t设定为负值, s u b s t r 函数将从右边开始计数。例如, s u b s t r( $ a , - 5)返回 $ a的最 后 5个字符。如果 l e n g t h设定为负值,则 s u b s t r返回从它的起点到字符串结尾的值,少于 l e n g t h 指明的字符,如下例所示: 在上面这个代码段中, s u b s t r 从位置 5 开始运行,返回字符串的剩余部分,但不包含最后 10个字符。 你也可以使用赋值表达式左边的 s u b s t r函数。当用在左边时, s u b s t r 用于指明标量中的什 么字符将被替换。当用在赋值表达式的左边时, s u b s t r的第一个参数必须是个可以赋值的值, 比如标量变量,而不应该是个字符串直接量。下面是使用 s u b s t r 对字符串进行编辑的一个例 子: 9.2 转换而不是替换 下一个运算符是转换运算符(有时称为翻译运算符) ,它使我们想起正则表达式中的替换 的操作方式。替换操作符的形式是 s/pattern/reptacement/,在第 6学时中我们已经作了介绍。除 非你用连接运算符=~设定了另一个标量,否则该操作符将对$ _ 变量进行操作。转换操作符 的作用与它有些类似,不过它并不使用正则表达式,而且它的运行方式完全不同。转换操作 符的句法如下所示: 转换操作符 tr///用于搜索一个字符串,找出 searchlist中的各个元素,并用 replacementlist中 的对应元素对它们进行替换。按照默认设置,转换操作符用于对变量$ _进行搜索和修改。若 要搜索和修改其他变量,你可以像使用正则表达式进行匹配操作那样,使用连接运算符,如 下所示: 字符的逻辑分组之间可以使用连字符。例如 A-Z 代表大写字母 A到Z,这样你就不必将它 们全部写出来,请看下例: 如果 replacementlist是空的,或者与 searchlist相同,那么 tr///将计算并返回匹配的字符。目 106 使用第二部分 高 级 特 性 下载 标字符串并不被修改,如下例所示: 最后要说明的是,由于历史的原因, t r / / / 也可以写成 y / / /,其结果相同,因为 y 与 t r 同义。 t r / / / 运算符(和 y / / /)也允许你为 s e a r c h l i s t和 r e p l a c e m e n t l i s t 设定另一组界限符。这些界限符可 以是任何一组自然配对的字符,如括号或任何其他字符,请看下面的例子: t r / / /运算符实际上还具备另外一些功能,不过用得不多。若要了解 t r / / / 能 够执行的所有其他任务,请查看 perlop节中的在线文档。 9.3 功能更强的print函数 p r i n t 函数是个非常简单的输出函数,它几乎不具备任何格式化功能。为了更具体地控制 输出操作,如左对齐和右对齐,十进制精度,以及固定宽度的输出,你可以使用 P e r l的 p r i n t f 函数。 p r i n t f函数是从 C编程语言那里借用的(几乎是原原本本的借用) ,不过其他编程语言也 配有类似的函数,如 BASIC的print using 函数。 printf函数的句法如下: f o r m a t s t r i n g是一个描述输出格式的字符串,下面我们很快就要对它进行介绍。 l i s t 是一个 你想让 p r i n t f 显示的值的列表,它类似 p r i n t 语句中的 l i s t。通常而言, p r i n t f将它的输出显示给 S T D O U T 文件句柄,但与 p r i n t一样,如果你设定了一个文件句柄,那么 p r i n t f就使用该文件句 柄。请注意, filehandle名与 formatstring 之间不使用逗号。 减号(可 有可无) 小数点 (可有可无) 域类型(必须有) 域限定 符标记 域的总宽 小数点后边的位 度(必须有) 数(可有可无) 通常情况下 f o r m a t s t r i n g 是个字符串直接量,它也可以是个用来描述输出格式的标量, formatstring中的每个字符均按其原义输出,但是以%开头的字符则属例外。%表示这是一个域 说明符的开始。域说明符的格式是% - w. d x , 表9-1 Printf 函数的部分域说明符列表 其中 w是域需要的总宽度, d是小数点左边的 位数(对于数字来说)和字符串域允许的总 宽度, x 表示输出的是数据类型。 x说明符前 面的连字符表示该域在 w 字符中左对齐,否 则它进行右对齐。只有%和 x是不可少的。表 9-1列出了一些不同类型的域说明符。 域类型 c s d f 含 义 字符 字符串 十进制整数;截尾的小数 浮点数 107 第9学时 其他函数和运算符使用 下载 完整的域说明符列表请参见在线手册。你可以在命令提示符后面键入 perldoc -f printf ,以 查看该列表。 下面是使用 printf的一些例子: 每个格式说明符均使用列表中的一个项目,如上所示。对于每个项目来说,都应该有一 个格式说明符;对于每个格式说明符来说,都有一个列表元素: 若要输出数字中的前导 0,只需要在格式说明符中的宽度的前面设置 1个0,如下所示: sprintf函数与 printf几乎相同,不过它不是输出值,而是输出 sprintf返回的格式化输出,你 可以将它赋予一个标量,或者用于另一个表达式,如下所示: 请记住,带有% f 格式说明符的 p r i n t f 和s p r i n t f函数能够将计算结果圆整为你指定的小数点 位数。 9.4 练习:格式化报表 当你使用计算机时,必然要处理的一项任务是将原始数据格式化为一个报表。计算机程 序能够按照不同于人类阅读的格式对数据进行交换,常见的任务是使用该数据,并将它格式 化为人能够阅读的报表。 为了进行这个练习,我们为你提供了一组员工记录,它包含关于某些虚构员工的信息, 包括每小时的工资、工作的小时数、名字和员工号码。这个练习使用这些数据将它们重新格 式化为一个很好的报表。 你可以很容易地修改这种类型的程序,以便输出其他类的报表。这个练习的数据包含在 一个在程序开始初始化的数组中。在真实的报表中,数据可能来自磁盘上的一个文件。后面 我们还要修改这个练习,以便使用外部的文件。 使用文本编辑器,键入程序清单 9 - 2 中的程序,并将它保存为 E m p l o y e e,不要键入行号。 按照第 1学时中的说明,使该程序成为可执行程序。 当完成上述操作后,在命令行提示符后面键入下面的命令,设法运行该程序。 Perl Employee 程序清单 9-1显示了 Employee程序的输出举例。 程序清单 9-1 Employee 程序的输出 108 使用第二部分 高 级 特 性 下载 程序清单 9-2 Employee 程序的完整清单 第1行:这一行包含到达解释程序的路径(可以更改这个路径,使之适合系统的需要)和 开关 -w。请始终使警告特性处于激活状态。 第3行: use strict 命令意味着所有变量都必须用 my进行声明,裸单词必须用引号括起来。 第 5 ~ 11 行:员工列表被赋予 @ e m p l o y e e s 。数组中的每个元素均包含名字、姓、员工号、 计时工资和工作的小时数。 第23~30行: @employees数组按姓和名字排序。 第 2 4 行:被排序的第 1 个元素($ a )分割为各个域。姓被赋予$ L 1 ,名字被赋于$ F 1 。 两者都用 my声明为排序块的专用变量。 第25行:对另一个元素$ b进行与上面相同的操作。姓名被赋于$ L2和$ L1 。 第 2 6 ~ 2 9 行:使用类似第 4 学时中的程序清单 4 - 1 介绍的顺序,按字母对各个名字进行比 较。 第32~34行: @employees中的已排序列表被传递给 print-emp() ,每次传递一个元素。 109 第9学时 其他函数和运算符使用 下载 第13~21行: print-emp() 函数输出格式化很好的员工记录。 第1 4 ~ 1 5 行:传递来的记录 $ _ [ 0 ] 被分割成各个域,并被赋于变量$ l a s t ,$ f i r s t 等,它们 都是该子例程的专用变量。 第17行:名字和姓被合并为单个域,这样,两个域就可以放入某个宽度,并一道对齐。 第1 8 ~ 2 0行:记录被输出。$ h o u r s 与$ t i m e 相乘,得出合计金额。金额 . 0 0 5 与合计相加, 这样,当乘积被截尾而成为两位数时,它能正确地圆整。 9.5 堆栈形式的列表 到现在为止,列表(和数组)一直是作为线性数据数组来展示的,其索引用于指明每个 元素。 0 1 2 3 4 5 苹果 桃 梨 李子 芒果 石榴 请使用你的想象力,将各个组数元素设想为一个纵向堆栈。 在计算机术语中,这种列表称为堆栈。堆栈可用于按顺序来处理的累计操作。 Klondike Solitaire 游戏就是一个很好的例子。 7堆牌中的每一堆牌分别代表一个堆 栈;开始时,这些牌面向下放入堆栈。当需要这些牌时,它们被翻过来,并从堆 栈中取走,再将其他牌放在新翻过来的牌的上面。 石榴 芒果 李子 梨 桃 苹果 Perl中的堆栈通常用数组来实现。若要将各个项目放在堆栈的顶部,可以使用 push函将项目压入堆栈;若要将项目从堆栈的顶部取出,可以使用 pop函数。 推送 菠萝 石榴 芒果 转移 葡萄 李子 梨 桃 弹出 转移 苹果 另外,堆栈可以从底部进行修改,可以将它视为从一叠纸牌的底部对它进行处理一样。 Shift函数用于将元素添加到堆栈的底部, unshift用于从底部取出元素。每个函数的句法如下: p o p 与s h i f t函数分别从 t a rg e t _ a r r a y 中删除一个元素。如果 t a rg e t _ a r r a y没有设定,那么元素 可以从 @_中删除,也可以从 @ARGV中删除。 pop 和shift函数返回被删除的元素,如果数组是 110 使用第二部分 高 级 特 性 下载 空的,则返回 undef。数组的大小将相应地缩小。 在子例程中,如果没有设定其他数组,那么 p o p、 s h i f t、u n s h i f t和 p u s h 函 数将修改 @_ 。在子例程外面,你的程序主体中,如果没有设定其他数组,那 么这些函数将修改数组 @ARGV。 p u s h 和u n s h i f t函数将 n e w _ l i s t 的元素添加给 t a rg e t _ a r r a y,数组的大小将增大,以适应放置 新元素的需要。被放入 targer_array 的项目,或者从 target_array取出的项目既可以是一个列表, 也可以是一个数组,如下例所示: 当你将元素添加给数组时,将元素推送(或移动)到数组中要比用手工 将元素添加到数组的结尾处更加有效。比如, p u s h ( @ l i s t , @ n e w i t e m s ) 比 @list=(@list,@newitems) 更加有效。 Perl的push、shift 、unshift和pup函数都 进行了优化,以适应这些操作的需要。 “堆栈”中的数组元素仍然属于标准的数组元素,可以用索引进行编址。堆栈的“底部” 是元素 0,堆栈的“顶部”是数组中的最后一个元素。 拼接数组 迄今为止,我们介绍了数组可以按元素进行寻址、分行、移动、弹出、取消移动和推送。 数组操作的最后一个工具是 splice 。splice函数的句法如下: s p l i c e 函数用于删除数组中从 o ff s e t 位置开始的元素,同时返回被删除的数组元素。如果 o ff s e t的值是负值,则从数组的结尾处开始计数。如果设定了 length,那么只删除 length指定的 元素。如果设定了 list,则删除 length 指定的元素,并用 list的元素取代之。通过这个处理过程, 数组就会根据需要扩大或缩小,如下面所示的那样: 9.6 课时小结 在本学时中,我们介绍了搜索其他字符串中的字符串时不需要使用正则表达式,你可以 111 第9学时 其他函数和运算符使用 下载 使用 i n d e x 和r i n d e x进行简单的索,也可以使用 t r / / / 运算符进行简单的替换。 s u b s t r函数既可 以用来从字符串中检索数据,也可以对它们进行编辑。你可以使用 printf和sprintf语句,用 Perl 创建格式很好的输出。另外,我们介绍了用作项目堆栈而不是平面列表的数组,还学习了如 何对这些堆栈进行操作。 9.7 课外作业 9.7.1 专家答疑 问题: s u b s t r、 i n d e x 和r i n d e x等函数真的有必要使用吗?当正则表达式可以用来执行它们 的大多数操作时,为什么还要这几种函数? 解答: 首先,用于进行简单的字符串搜索的正则表达式的运行速度比 i n d e x 和 r i n d e x 慢。 第二,为字符位置固定的正则表达式编写替换表达式会产生很大的混乱,而有时 s u b s t r则是比 较出色的解决方案。第三, Perl是一种丰富多彩的语言,你可以使用你喜欢的解决方案,你可 以有多种多样的选择。 问题: 如果我设定的索引位于标量的结尾之外,使用 s u b s t r (或 i n d e x 或 r i n d e x)将会出现 什么情况? 解答 :计算机的好处之一是:它具有很强的一致性,而且它有很强的耐心。对于“如果 …将会出现什么情况”之类的问题,有时你只要试一试它的最容易实现的方法即可!什么是 可能出现的最坏情况呢? 在这种情况下,如果你激活了警告特性,那么访问并不存在的标量的某个部分,就会产 生一个“ use of undefined value ” (使用了未定义的值)的错误。例如,如果你使用$ a = “Foo ”; substr($ a,5);那么 substr函数将返回 undef。 9.7.2 思考题 1) 假如有下面这个代码,那么在 @A中将留下什么? a. oats peas beans b. deans barley c. peas beans barley 2) printf ( “%18.3f” ,$ a)这个代码能够进行什么操作? a. 它输出一个浮点数,长度为 1 8 个字符,小数点左边是 1 5 个字符,小数点右边是 3 个 字符。 b. 它输出一个浮点数,小数点左边是 18个字符,小数点右边是 3个字符。 c. 它输出一个浮点数,长度为 18个字符,小数点左边是 14个字符,右边 3个字符。 3) 如果对一个字符串运行 tr/a-z/A-Z,tr/A-Z/a-z能否使字符串恢复其原始形式? a. 是,当然能够。 b. 也许做不到。 112 使用第二部分 高 级 特 性 下载 9.7.3 解答 1) 答案是 c 。s h i f t 删除了 c a t s,而 p u s h则将 b a r l e y 添加到结尾处。最后的 p o p是个假像,它 并没有设定任何数组,因此它从 array @_ 中弹出某些数据,但是它没有给 @A带来任何变化。 2) 答案是 c。如果你猜测的答案是 a ,那么你没有将小数点计算在内,它在总数( 1 8= 1 4 +1+3)中占有一个位置。 3) 答案是 b 。t r / a - z / A - Z / 转换的“ r o s e b u d ”变成了“ R O S E B U D” 。如果试图用 t r / A - Z / a - z / 将它变回原样,那么产生的是“ rosebud ” ,而不是原始字符串。 9.7.4 实习 • 使用标量而不是数组,重新编写第 4学时中的 H a n g m a n游戏。你可以使用 s u b s t r ,对标量 中的各个字符进行操作。 • 修改程序清单 9 - 2,从文件中读取数据,而不是从数组中获取数据。打开文件,将数据 读入一个数组,然后按正常情况继续操作。当然你必须在磁盘上创建该文件。 ...
View Full Document

This note was uploaded on 11/27/2011 for the course CS Perl taught by Professor Guo during the Spring '09 term at Xiamen University.

Ask a homework question - tutors are online