给perl 5.10初学者的介绍
作者:chromatic , Doug Sheppard
翻译:WWW.17LAMP.NET JianXin.
繁体转换工具:网页线上转码
校正:ㄚ琪
首先,一个小小的促销
作者的注释:这个系列是基于Doug Sheppard的 Beginner’s Introduction to Perl的, A Beginner’s Introduction to Files and Strings with Perl 5.10解释如何使用档案和字串,A Beginner’s Introduction to Regular Expressions with Perl 5.10探究正规表示式、比对及取代, A Beginner’s Introduction to Perl Web Programming 说明如何写web程式。
欢迎来到Perl。
Perl 是Swiss Army 程式设计语言的一部分:功能强大并且很容易学习。它首先是被Larry Wall 开发的。一位在1980年代末在NASA任系统管理员的语言学家,作为一种使得报告工作更加容易的方法。自那以后,它已经进入很多不同的领域:自动管理系统,作为不同电脑系统之间的连结、网路程式、生物资讯、资料整理,甚至应用程式的开发。
为什么Perl会变得如此的流行当网络随之而来之时?有两个原因:首先,大部份在网路上所作的事是关于文字的,而这最好是用一个专门设计用来处理文字的语言来处理。更重要的是,当人们需要使用一些东西时Perl比其他的选择更加好。C语言很复杂并且可能产生安全问题(尤其是有不可信任的资料时),Tcl很难用,Python没有一个真正的立足点。
Perl是一种友好的语言。它与你的个人的程式设计风格能够很好的配合。Perl的口号是“有一种以上的方法来作一件事。”那使得它可以同时解决大的和小的问题。更多的是,Perl是可移植的并且普遍的--它几乎可以在任何机器上预先安装--当然在CPAN还有很多自由发行的函式库。
这是我们的系列的第一部分,你将会学习一些有关Perl的基础知识并会看到一个小的范例程式。
关于作业系统的一些话
这个系列假设你正在使用一个Unix或者Unix-like操作系统( Mac OS X 和 适合使用Cygwin)并且在/usr/bin/perl你有一个可用的Perl函式库。如果你在Windows使用ActivePerl 或者 Strawberry Perl那也是可以的;大多数的Perl的程式码是与平台无关的。
第一个Perl程式
把这个文件存为first.pl:
use feature ‘:5.10’;
say “Hi there!”;
(传统的第一个程式:对世界说Hello!但是我是一个传统叛逆者。)
执行这个程式。在命令列,进入文件的所在目录并且输入:perl first.pl。你应该看到:
Hi there!
很友好,不是吗?
我敢保证你会猜测程式是什么意思。use feature ‘:5.10’;一行是什么?现在,你所需要知道的是它允许你好好地使用在Perl 5.10中的新特性。这是件非常好的事。
函数和陈述
Perl有很丰富的内建函数的函式库。它们是Perl的动词,是解译器执行的命令。你可以在perlfunc的man手册(在命令列中输入 perldoc perlfunc)中看到一个内建函数的列表。几乎所有的函数都会有一个有逗号隔开的参数列表。
print函数是Perl最常使用的一部分。你用它来在荧幕上显示东西或者发送消息到一个文件。它使用一个事物的列表作为它的参数。
print “This is a single statement.”;
print “Look, “, “a “, “list!”;
一个Perl程式包含叙述,每个叙述都以一个分号结束。叙述不需要在分开的行;可能在一行中有很多的叙述。你也可以分开单一的一个叙述在不同的行。
print “This is “; print “two statements.\n”;
print “But this “, “is only one statement.\n”;
但是等一下。say和print之间的区别是什么呢?在print叙述中的\n是什么?
say函数就像print函数,除了它会添加一个跳行在参数的末端之外。它会输出所有的参数和一个跳行字元。其它就没什么区别了。print,另一方面,只是输出在这些例子中你确实看到的。如果你想要跳行,你必须增加一个特殊字元\n。
use feature ‘:5.10’;
say “This is a single statement.”;
say “Look, “, “a “, “list!”;
为什么它们都会存在呢?为什么你会使用它们两个?通常,大多数“显示一些东西“叙述需要跳行。say通常就足够了,它是一个很好的预设选择。偶尔你需要对你的输出有少许的控制,所以print就可以选择。
记住say比print少两个字元。这是perl一个重要的设计原则--常见的事情应该是容易和简单的。
数字、字串和引号
在Perl中有两个基本的资料类型:数字和字串。
数字很简单;我们已经处理过了它们。你仅仅需要做得是你需要知道在Perl中,你不可以在数字中输入逗号或者空格。可以写10000,但不可以写10,000或者10 000。
字串会有些复杂。一个字串是一个在单引号或者双引号中的字元的集合:
‘This is a test.’
“Hi there!\n”
单引号和双引号之间的区别是单引号意味着它们的内容被认为是逐字的字串,而双引号则意味其内容可以被解译的。
记得字元\n吗?它代表一个跳行当它出现在一个双引号的字串中时,但是如果是在单引号的字串中那就只是逐字解译成一个斜线及一个n的字元。
use feature ‘:5.10’;
say “This string\nshows up on two lines.”;
say ‘This string \n shows up on only one.’;
(另外两个有用的斜线字元是\t用来插入一个tab字元,\\用来插入一个斜线到一个双引号中的串。)
变数
如果说函数是Perl的动词,那么变数就是名词。Perl有三种类型的变数:纯量、阵列和杂凑。分别把它们看成事物、列表和字典。在Perl中,所有可用的名字包含一个标点符号、一个字母或者底线,一个或者多个混合符号的字母或者底线。
纯量是一个单一的事物。这可能是一个数字或者一个字串。纯量的名字用一个美元符号开始,比如$i或者$abacus。指定一个值给一个纯量告诉Perl它等于什么:
my $i= 5;
my $pie_flavor= ‘apple’;
my $constitution1776 = “We the People, etc.”;
你不需要特别指出一个纯量是一个数字还是一个字串。这并不重要,因为Perl需要以字串的方式处理一个纯量,它就会这样去做;它需要把它当作数字,它也会这么做。这种对话会自动发生。(这是与其它的语言不同的地方,在其它语言中字串和数字是两种分开的资料类型。)
如果你使用一个双引号的字串,Perl将会插入任何在字串中你命名的纯量变数的值。直接填充一个字串时很有用:
use feature ‘:5.10’;
my $apple_count= 5;
my $count_report = “There are $apple_count apples.”;
say “The report is: $count_report”;
这个程式码的最后的输出是:he report is: There are 5 apples..
你在Perl中可以控制数字来作一般的数学运算:加法,乘法,除法和减法。(顺便说一下,在Perl中乘法和除法的运算元使用*和/。)
my $a = 5;
my $b = $a + 10;# $b is now equal to 15.
my $c = $b * 10;# $c is now equal to 150.
$a= $a – 1;# $a is now 4, and algebra teachers are cringing.
这些都是很好的,但是奇怪的是my是什么呢?为什么有些有有些没有?这个运算元告诉Perl你宣告了一个新的变数。也就是说,你向Perl保证在你的程式中你想要使用一个特别的纯量、阵列或者杂凑。这很重要,有两个原因。首先,它帮助Perl帮助你保护输入的内容;那会是很尴尬的当你发现你突然打错了一个变数名字,花费了一个小时来找到这个漏洞。第二,它帮助你写更大的程式,这里被使用在程式码的一部分的变数不会影响到其他地方使用的变数。
你也可以使用特别的运算元,比如说++,–,+=,-=,/=和*=。它们在一个等式中操作一个纯量的值而不用两个元素。一些人喜欢它们,另一些却不是。我喜欢这个事实它们会使得程式码更简洁。
my $a = 5;
$a++;# $a is now 6; we added 1 to it.
$a += 10;# Now it’s 16; we added 10.
$a /= 2;# And divided it by 2, so it’s 8.
在Perl中的字符串没有这样的自由性。仅有的基础的你可以在字符串中使用运算符是连接运算符,这是一种“放在一起”的说法。这个连接运算符就是句号。连接和加法运算符是两个不同的事物:
my $a = “8”;# Note the quotes.$a is a string.
my $b = $a + “1”;# “1” is a string too.
my $c = $a . “1”;# But $b and $c have different values!
记住Perl会在任何必要的时候自动的转化字串为数字,所以要得到$b的值,Perl解译器会把两个字串“8”和“1”转化为数字,然后将它们相加。$b的值变为数字9。然而,$c使用连接运算元,它的值会是字串“81”。
记住,加号用来操作数字而点号用来将字串连在一起。如果你对不是数字的事物做加法运算,Perl会尽最大努力来完成你让它去做的工作,并且转换那些不是数字的事物为数字。
阵列是一个纯量的列表。阵列名用@开始。你通过在括号中列出它们的内容来定义一个阵列,元素用逗号隔开:
my @lotto_numbers = (1, 2, 3, 4, 5, 6);# Hey, it could happen.
my @months= (“July”, “August”, “September”);
你用索引来跟踪一个阵列,比如“Hey, give me the first month of the year.”。在Perl中索引从零开始。(为什么不是1?因为,这是计算机的事情。)要跟踪一个阵列的元素,你需要把@替换成$,紧接着是你想要的元素的索引位置(它以一个美元符号开头因为你正在获得一个纯量值。)你也可以就地修改它,就像任何其他的纯量。
use feature ‘:5.10’;
my @months = (“July”, “August”, “September”);
say $months[0];# This prints “July”.
$months[2] = “Smarch”;# We just renamed September!
如果一个阵列值不存在,Perl会当你给它赋值时为你建立它。
my @winter_months = (“December”, “January”);
$winter_months[2] = “February”;
阵列总会以同样的顺序返回它们的内容;如果你遍历@month,无论你做多少次,你总会以July, August, September 的顺序得到它们。如果你想要找出阵列的元素个数,把这个阵列赋值给一个纯量。
use feature ‘:5.10’;
my @months= (“July”, “August”, “September”);
my $month_count = @months;
say $month_count;# This prints 3.
my @autumn_months; # no elements
my $autumn_count = @autumn_months;
say $autumn_count; # this prints 0
一些程式语言把杂凑叫做“字典”。那就是因为:一个字和一个定义。更准确的说,它们包含键和值。每个在杂凑中的键都仅有的一个相对应的值。杂凑的名称以一个百分号开始,你用逗号隔开的键和值来定义杂凑,就像这样:
my %days_in_month = ( “July” => 31, “August” => 31, “September” => 30 );
你可以得到任何杂凑中的值通过 $hashname{key},或者就地修改它就像其他的纯量。
say $days_in_month{September}; # 30, of course.
$days_in_month{February} = 29; # It’s a leap year.
要查看一个杂凑中的键,使用keys函数和杂凑的名字。这个函数传回一个包含所有杂凑键的一个阵列。这个阵列不会总是相同的顺序;而你可以相信@month总是以同样的顺序传回 July, August, September, keys %days_in_summer可能会以任何顺序传回它们。
my @month_list = keys %days_in_summer;
# @month_list is now (‘July’, ‘September’, ‘August’)!
这三种类型的变数有三个不同的命名空间。那就意味着$abacus和@abacus是两个不同的变数,并且$abacus[0](@abacus的第一个元素)与$abacus{0}(键值为0的%abacus的值)是不同的。
注解
一些前面部分的程式码的例子包含程式码注解。这对于解释一个特别的程式码片段是很有用的,并且对于任何一个你想要修改,改进,修理或者只是看一看的程式码片段也是很重要的。(也就是说,注解很重要。)
任何一行Perl程式码跟随一个#作为注解,除非#出现在一个字串中。
use feature ‘:5.10’;
say “Hello world!”;# That’s more like it.
# This entire line is a comment.
回圈
几乎每一种程式都会使用回圈。回圈允许你重复执行同一个程式码片段。这是程式设计中一般观念的一部分叫做流程控制。
Perl有一些不同而有用的流程控制函数,最基础的是for。当你使用for函数时,你指定一个变数用作回圈索引,一个列表的值用来作为回圈的内容。在一对大括号之间,你可以写你想要回圈完成的程式码:
use feature ‘:5.10’;
for my $i (1, 2, 3, 4, 5) {
say $i;
}
这个回圈输出1到5的数字,每行输出一个。(这不是很有用;你可能想“为什么不写say1,2,3,4,5;?”这是因为say只会跳一行,在它的参数列表的末端。)
有一个方便捷径可以定义回圈值叫做范围 运算元 ..,用来指定一个范围的数字,你可以写(1, 2, 3, 4, 5) 成为(1 .. 5),你也可以在你的回圈列表使用阵列及纯量,试试程式码并看看发生什么事:
use feature ‘:5.10’;
my @one_to_ten = (1 .. 10);
my $top_limit= 25;
for my $i (@one_to_ten, 15, 20 .. $top_limit) {
say $i;
}
当然,你又一次可以写say @one_to_ten, 15, 20 .. $top_limit;
在你的循环列表中的事物不一定是数字;你可以方便的使用字符串。如果散列%month_has包含月份名称和每个月的天数,你可以使用keys函数来便利它们:
use feature ‘:5.10’;
for my $i (keys %month_has) {
say “$i has $month_has{$i} days.”;
}
for my $marx (‘Groucho’, ‘Harpo’, ‘Zeppo’, ‘Karl’) {
say “$marx is my favorite Marx brother.”;
}
复利的奇迹
关于Perl你现在已经知道足够多了--变数、print/say和for()--来写一个小的、有用的程式。每一个人都喜欢钱,所以第一个例子是一个复利计算器。它将会输出一个格式工整的表格显示一个在投资几年之后的值(你可以在 compound_interest.pl中看到程式)
程式中最复杂的的一行是:
my $interest = int( ( $apr / 100 ) * $nest_egg * 100 ) / 100;
$apr / 100 是利率,($apr / 100) * $nest_egg 是一年之内的利息。这一行使用了int()函数,它会返回一个整数的纯量值(它的值省略掉所有的小数部分)。我们在这里使用int()是因为如果你相乘,比如说,10925乘以9.25%,结果是 1010.5625,我们必须舍入到1010.56。要做这些,我们要乘以100,得到 101056.25,使用int()来扔掉多余的小数部分,得到101056,然后再被100除,最后的结果是1010.56。试着自己跟着这个程式码来看看我们是怎样得到最后的正确答案。
玩一玩!
现在你有了一些基本的Perl语法的知识并且一些简单的玩具。试着用它们写一些简单的程式。这里有两点建议,一个很简单,另一个有一些复杂:
- 一个字频计数器。在一个阵列中,一个字出现的频率是多少?输出结果(提示:用一个杂凑来记录每个文字出现的次数)
- 给出一个月和一个星期的天数作为这个月的第一天,输出一个这个月的日历。