Perl 5.10 入门教程

首先,一点推销

编辑注:本系列基于Doug SheppardPerl 入门教程。使用Perl 5.10的文件和字符串入门教程解释了如何使用文件和字符串,而使用Perl 5.10的正规表达式入门教程探讨了正规表达式、匹配和替换。入门教程Perl网络编程展示了如何编写网络程序。

欢迎来到Perl的世界。

Perl是编程语言的瑞士军刀:强大且灵活。它最初由Larry Wall开发,他在20世纪80年代末作为NASA的系统管理员工作,是一名语言学家,目的是使报告处理变得更简单。从那时起,它已经进入到了几个其他领域:自动化系统管理、作为不同计算机系统之间的粘合剂、网络编程、生物信息学、数据处理,甚至应用开发。

为什么Perl在互联网出现时变得如此流行?有两个原因:首先,互联网上所做的大部分事情都是与文本相关的,并且最好用一种专为文本处理设计的语言来完成。更重要的是,Perl在人们需要使用某种东西的时候,比当时可用的替代品要好得多。C语言复杂,可能会产生安全问题(特别是与不受信任的数据一起使用时),Tcl可能有些笨拙,而Python当时并没有立足之地。

Perl也是一个友好的语言。它与你的个人编程风格配合得很好。Perl的口号是“条条大路通罗马”,这对大小问题都适用。更重要的是,Perl非常便携和普及——几乎到处都可以预装——当然,从CPAN有数千个可以自由分发库可用。

在本系列的第一个部分,你将了解一些关于Perl的基本知识,并看到一个小样程序。

关于操作系统的说明

本系列假设您正在使用Unix或类Unix操作系统(Mac OS X和Cygwin符合条件),并且您在/usr/bin/perl处有可用的perl二进制文件。如果您通过ActivePerl或Strawberry Perl在Windows上运行,那也行;大多数Perl代码都是平台无关的。

您的第一个Perl程序

将此程序保存为名为first.pl的文件

use feature ':5.10';
say "Hi there!";

(传统的第一个程序是说Hello world!,但我不是传统主义者)。

运行程序。从命令行进入包含此文件的目录,并输入perl first.pl。你应该看到

Hi there!

友好,不是吗?

我敢肯定你能猜到say的作用。关于use feature ':5.10';这一行呢?现在你只需要知道,它允许你使用Perl 5.10中发现的不错的新特性。这是一件非常好的事情。

函数和语句

Perl有一个丰富的内置函数库。它们是Perl的动词,是解释器执行的命令。您可以在perlfunc手册页(从命令行使用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";

等等。那么sayprint有什么区别?print语句中的\n是什么意思?

say函数的行为与print函数类似,但它会在其参数的末尾追加一个换行符。它打印所有的参数,然后是一个换行符。总是这样。没有例外。print,另一方面,只打印您在这些例子中明确看到的内容。如果您想要换行,您必须使用特殊的转义序列\n自己添加。

use feature ':5.10';

say "This is a single statement.";
say "Look, ", "a ", "list!";

为什么两者都存在?为什么您会选择一个而不是另一个?通常,大多数“显示某些内容”的语句都需要换行。这很常见,所以say是一个好的默认选择。偶尔您需要更多一点的控制权,所以print是选项。

请注意,sayprint短两个字符。这是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用于插入制表符,以及\\用于在双引号字符串中插入反斜杠。)

变量

如果函数是Perl的动词,那么变量就是其名词。Perl有三种类型的变量:标量数组哈希。分别考虑它们为事物、列表和字典。在Perl中,所有变量名都由一个标点符号、一个字母或下划线,以及一个或多个字母数字字符或下划线组成。

标量是单个事物。这可能是一个数字或一个字符串。标量的名称以美元符号开始,例如$i$abacus。通过告诉Perl它等于什么来给标量赋值

my $i                = 5;
my $pie_flavor       = 'apple';
my $constitution1789 = "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";

此代码的最终输出是报告如下:有5个苹果。

您可以使用通常的数学运算在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是什么,为什么它只出现在某些赋值中而不是其他地方?my运算符告诉Perl你正在声明一个新的变量。也就是说,你向Perl承诺你故意想要在你的程序中使用具有特定名称的标量、数组或哈希。这有两个原因。首先,它帮助Perl帮助你防止打字错误;发现你不小心打错了变量名,花了几个小时找bug是很尴尬的。其次,它帮助你编写更大的程序,其中一个部分使用的变量不会意外地影响其他地方使用的变量。

你还可以使用特殊的运算符,如++--+=-=/=*=。这些运算符可以在不需要方程中的两个元素的情况下操作标量的值。有些人喜欢它们,有些人不喜欢。我喜欢它们可以使代码更清晰。

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");

你可以通过一个索引来检索数组的内容,有点像“嘿,给我一年的第一个月”。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";

数组总是以相同的顺序返回它们的元素;无论你多少次从开始到结束遍历@months,你都会以同样的顺序得到七月八月九月。如果你想找到数组的元素数量,将数组赋给一个标量。

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

一些编程语言将哈希称为“字典”。这就是它们的含义:一个术语和一个定义。更确切地说,它们包含。哈希中的每个键都只有一个对应的值。哈希的名称以百分号开头,例如%parents。你通过逗号分隔键和值的对来定义哈希

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函数。这返回一个包含哈希中所有键的列表。列表不一定按顺序排列;虽然你可以确信@months总是以七月八月九月的顺序返回,但keys %days_in_month可能以任何顺序返回。

my @month_list = keys %days_in_month;
# @month_list is now ('July', 'September', 'August', 'February')!

这三种类型的变量有三个不同的命名空间。这意味着$abacus@abacus是两个不同的变量,而且$abacus[0]@abacus的第一个元素)不等于$abacus{0}(在%abacus中具有键0的值)。

注释

上一节的一些代码示例包含了代码注释。这些注释对于解释特定代码片段的功能非常有用,对于任何计划修改、增强、修复或再次查看的代码来说都是至关重要的。(也就是说,注释很重要。)

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的数字,每个数字占一行。(它不是很实用;你可能想“为什么不直接写say 1, 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/sayfor()——可以编写一个小的、有用的程序。每个人都喜欢钱,所以第一个示例程序是一个复利计算器。它将打印出一个格式较好的表格,显示投资在多年后的价值。(你可以在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语法有一些基本的了解,还有一些简单的玩具可以玩。试着用它们编写一些简单的程序。这里有两个建议,一个简单,另一个稍微复杂一些。

  • 一个单词频率计数器。每个单词在单词数组中出现了多少次?打印出一份报告。(提示:使用哈希来计算每个单词的出现次数。)
  • 给定一个月份和该月第一天的星期,打印出该月的日历。

标签

反馈

这篇文章有什么问题吗?请帮助我们通过在GitHub上打开一个issue或pull request来解决问题。