Learning Perl(持续更新)

总述:

这篇文章是我在阅读 Learning Perl (Randal Schwartz, Tom Phoenix, brain d foy, 2008, O'Reilly Media 978-0-596-52010-6)(又称小骆驼书) 时做的笔记。

当然通过阅读这些笔记可能使你比起阅读原书更加快速的上手Perl,但是如果你有足够的时间我会推荐去阅读原书来形成比较流畅而且牢固的知识体系,而且我可能会在这篇笔记中填入一些自己先入为主的观念,这对你的学习可能会造成一点影响。

如果你找到错误或者不严谨的表述,欢迎你来信告诉我。我的联系方式可以在 About 页面中找到。

1 CH.1 Introduction

这一章没有多少有关Perl技术上的论述。

大部分都是对于本书、其作者以及Perl的介绍和几页FAQ,所以在这里跳过。

有兴趣的读者可以去阅读原书。

2 CH.2 Scalar Data

当然这里所指的Scalar与数学、物理领域内的Scalar并不相同。Scalar只是对Perl当中一种数据泛类型的称呼。 Scalar通常(大部分情况下)以数字或字符串的形式表现。这里我们可以先将数字与字符串独立审视,就像其他的编程语言那样。 p** Numbers 我们可以先看数字这部分。

2.0.1 Decimal Numbers

在Perl,所有的数字内部都是以相同的格式存在。你可以指定整数或者浮点数,但是在Perl内部都是以双精度浮点数( double-precision floating-point value )进行计算的。 所以可以理解为对于Perl不存在整数。所有的“整数”都是以 DPFP 类型进行计算的。

所以以下这些数字在Perl都是合法的。 25, 25.5, 25.255, 25.0, 25.000, 25e25, -25e25, -25e-25

在Perl中,数字通过下划线标记位数是允许的。 例如:

1000000 可以被写为 1_000_000 ,这在Perl内部是相同的两个数字。

2.0.2 Nondecimal Integer

在编程中,非十进制数字使用最广泛的有:二进制 binary 、八进制 octal 、十六进制 hexademical 。 二进制用 0b 标识,八进制用 0 ,十六进制用 0x 。所以以下的数字都是 相同 的。

0b1010 012 0xA 10 10.000

当然,对于非十进制的数字也可以用下划线标记位数,例如 0b10_11_10_00 是合法的。

需要注意的是,所谓的 "Leading zero" Indicator 只针对于普通的Literal数据,自动的字符串->数字变换是不支持的。也就是说你不可以将 "0b11" 这个字符串与 3 等同,但是 0b11"3" 可以。 你可以使用 oct()hex() 函数进行字符串到非十进制数字之间的转换。

2.0.3 Numeric Operators

Perl当然支持最普通的四则运算 + - * / 与模运算 % ,当然也支持浮点数与整数混合运算。 在浮点数进行模运算时,Perl会自动将浮点数取整,所以 15.6 % 2.415 % 2 结果相同。

Perl同时也支持幂运算,例如 2**3 结果为 8

当你需要计算负数的分数幂的时候,你可以调用 Math::Complex 模块进行复数运算。

Perl还有其他一些数字运算符,当我们需要的时候会进行讲解。

2.1 Strings

字符串可以理解为串在一起的一堆字符。

2.1.1 Single and Double Quoted Strings.

原书中有一段话:

This is in accordance with the principle of “no built-in limits” that Perl follows at every opportunity.

所以你既可以在一段字符串中加入可打印的字符,也可以加入不可打印的字符,比如二进制数据,然后对他们进行各种操作。这在Perl内都是合法的。

Perl内的字符串有两种表示形式, Single-Quoted String LiteralsDouble-Quoted String Literals

在单引号字符串中,只支持单引号 ' 与反斜杠 \ 的字符转义,所以,单引号字符串是最简单最纯粹的字符串表示形式。

然而,在双引号字符串中,支持所有的转义字符,换行 \n ,制表符Tab \t,和对ASCII值的引用等。

同时,你可以在双引号字符串中插入变量,所以,

$foo = "bar";
print "$foo is bar";

结果会输出 bar is bar

2.1.2 String Operators

字符串之间可以通过 . 进行连接,对,就是一个点。 所以:

"hello"."world" == "hel"."lowo"."rld"

字符串可以用 x 字符进行复制倍增, x 前的Literal会被视为字符或字符串,其后的Literal会被视为数字,所以:

"foo" x 3 == "foo" x "3" == "foofoofoo"
"5" x "3" == 5 x "3" == 5 x 3 == 5 x 3.3 == 5 x "3.3" == 555

当倍增的数字小于1时,会输出空字符串 ""

这是关于Perl一个神奇的特性。

2.1.3 Automatic Conversion Between Numbers and Strings

关于这部分,原书有很好的诠释:

For the most part, Perl automatically converts between numbers and strings as needed.How does it know which is needed? It all depends upon the operator being used on thescalar value. If an operator expects a number (like + does), Perl will see the value as anumber. If an operator expects a string (like . does), Perl will see the value as a string.So you don’t need to worry about the difference between numbers and strings; just usethe proper operators, and Perl will make it all work.

所以:

"12" * "3" == 12 * 3 == 36
"12foo" * "3bar" == 36

但是在执行第二条计算的时候,Perl会抛出一个Warning: Argument "3bar" isn't numeric in multiplication (*) 所以可以视为,当一个数字与字母混合的字符串被转换为字符时,Perl会在字符串头部寻识别数字,如果没有则返回0.

2.2 Perl's Built-in Warnings

在这里需要插入一个Perl内置警告的单元。

如果你要开启Perl的内置警告,可以在运行脚本时使用 -w 参数,或者直接在脚本头部添加 -w 参数,例如

$ perl -w some_script

或者:

#!/usr/bin/perl -w

甚至简略为:

#!perl -w

在Perl5.6或更新的Perl中,你可以这样写:

#!/usr/bin/perl
use warnings;

当你需要更长的诊断类描述时,可以这样写:

#!/usr/bin/perl
use diagnostics;

显然,这样做会使程序运行得更慢一些,当你不需要或者已经编写或Debug完了程序,应该注释掉这一行。

但是对于这种Diagnostic有一种优化便是使用 -M 参数,原书对于 -M 参数的诠释是这样的:

A further optimization can be had by using one of Perl’s command-line options, -M, toload the pragma only when needed instead of editing the source code each time toenable and disable diagnostics.

2.3 Scalar Variables

A variable is a name for a container that holds one or more values. The name of thevariable stays the same throughout the program, but the value or values contained inthat variable typically change over and over again throughout the execution of theprogram.

所以在Perl中变量的特性与用法在其他编程语言中并没有区别。

在Perl中一个scalar variable只能储存一个scalar value,

但是Perl中的Scalar Variable需要一个代表变量名的符号,以便与其他Literals区别开来,在这里使用的是美元符号 $ 。 在Perl中这类符号称作 Sigil , 对于不同的变量需要不同的Sigil,在后面 变量名(通常使用的表述是 Perl Identifier )不可以以数字开头,而且大小写区分。

2.4 Scalar Assignment

对于Scalar Variable的赋值操作,与其他的编程语言大致相似。赋值操作通过 = 来进行,例如:

$foo = 3;
$foo = $foo + 3;
$foo += 3;
$foo = "bar";
$foo = $foo . "foo";
$foo = $foo x 3;
$foo x= 3;
$foo .= "foo";

类似的操作都是合法的。

2.5 Output with print

Perl中的 print() 函数与其他语言中的类似,而且可以携带或不携带括号 () 。例如:

print "hello world\n";    # 输出为 “hello world”以及一个新行。

print "the answer is ";
print 2*3;
print ".\n";    # 输出为“the answer is 6.”以及一个新行。

# 当然也可以这么操作。

print "the answer is". 6*7 .".\n";

# 输出是相同的。

2.6 Interpolation of Scalar Variables into Strings

在双引号字符串中引用scalar variable,可以自动替换为该变量的值。例如:

$foo = "bar";
print "$foo is bar";

结果会输出 bar is bar

在被引用的变量没有被赋值或声明时,会以 "" (空字符串)或 0 来代替。

注意,这种Interpolation只能在双引号字符串中进行,单引号字符串是没有这种效果的。

同时,在这种Interpolation中,Perl会寻找所谓的 Longest Possible Variable ,所以为了避免程序出Bug,你可能想要用一些可用的分割符来进行变量名与字符串之间的分割。 例如:

$foo = 1;
$foobar = 2;
print "$foos";        #会输出“1s”
print "$foobar";      #会输出“2”
print "$foo"."bar";   #会输出“1bar”
print "${foo}bar";    #会输出“1bar”

2.7 Operator Precedence and Associativity

操作优先级这方面没有什么好讲的,Perl的各种操作优先级(包括二进制位操作)都与C语言相同。

So should you just memorize the precedence chart? No! Nobody actually does that.Instead, just use parentheses when you don’t remember the order of operations, orwhen you’re too busy to look in the chart. After all, if you can’t remember it withoutthe parentheses, your maintenance programmer is going to have the same trouble. Sobe nice to your maintenance programmer: you may be that person one day.

2.8 Comparison Operators

对于数字之间的比较,Perl有以下几种操作符:

< <= == >= !=

他们进行判断的返回值都是真或假 true / false

对于字符串之间的比较,Perl有以下集中操作符:

lt le eq ge gt ne

分别代表 less than , less or equal , equal , greater or equal , greater than , not equal

Perl中字符串的比较方法是从头至为比较单个字符的ASCII值,而且需要注意的是在ASCII码表中大写字母在小写字母前面,所以表达式 "Ab" lt "ab" 返回 true

2.9 The if Control Structure

又到了喜闻乐见的条件选择环节。

在Perl中, if 结构与C语言大致相同,例如:

if (<condition>){
    # do something;
}  elsif (<condition>) {
    # do another something;
}  else {
    # ok let's do this;
}

在Perl的if语句中,括号是必须的。

Condition 返回的可以为True or False,当Condition为一个数字,除0外所有数字均为 True ,当Condition为一个字符串,除了空字符串 '' 以外所有字符串均为真,否则(该Scalar Data为除字符串或数字以外的值)将该值转换为数字或字符串然后在进行判断。

而且这里有一个little trick:在Perl中字符 '0' 与数字 0 是可互相转化的,所以 '0' 是Perl中唯一可以被判断为假的非空字符串。

2.10 Getting User Input

在Perl中获取输入有一种很简单的方式, <STDIN> ,例如:

$foo = <STDIN>;

需要注意的是,<STDIN>返回的是一串字符串,以换行符做结尾,所以<STDIN>的返回值不可能是空字符串,最短返回值为 '\n'

但是在大部分情况下并不需要这个结尾的换行符,所以我们需要另一个函数去去除输入时的换行符。

2.11 The chomp Operator

chomp() 的使用方法类似这样:

$foo = <STDIN>;
chomp($foo);    # 这里的括号是可以省略的。

或者再短一点:

chomp($foo=<STDIN>);    #这里的括号不可以省略。

作为一个函数, chomp() 是有返回值的,它会返回去除的字符的数量————通常情况下这个数字为1,因为在有多个换行符作为末尾的情况下, chomp() 也只会移除一个。但是当输入为空字符串或无末尾换行符的字符串, chomp() 会返回0。

2.12 The while Control Structure

又是一个十分常用的结构。同样,Perl的while语句也和C类似:

while(<condition>){
    # do something;
}

condition 的判断方式已经介绍过,这里不再赘述。

2.13 The undel Value

Perl的一个很有趣的特性便是这个 undef 值,它适用于引用未声明或赋值的变量时,可以被自动转换为 0'' ,所以:

$unassigned_variable = "foo";

$another_unassigned_variable .= "foo";

两者是相等的。

原书中写道:

Many operators return undef when the arguments are out of range or don’t make sense…. But you should know that when warnings are turned on, Perl willtypically warn about unusual uses of the undefined value, since that may indicate abug. For example, simply copying undef from one variable into another isn’t a problem,but trying to print it would generally cause a warning.

2.14 The defined Function

<STDIN> 操作通常会返回一个字符串,但是也有特例。当你在扫描一个文件时,如果遇到 EOF ,那么 <STDIN> 会返回 undef ,这时你可以用 defined() 函数来判断某个变量是否被赋值。 defined() 当输入的值为 undef 时返回假,其他情况均返回真。

当然,你也可以为某个变量赋值 undef ,虽然这与没声明该变量没有什么区别,但是某些情况下这个特性是很有用的。

3 CH.3 List and Arrays

3.1 TODO Finish this later.