在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
参考地址:http://qntm.org/files/perl/perl_cn.html Perl是一门动态的、动态类型的高阶脚本(解释型)语言,常常与PHP和Python相提并论。Perl的语法借鉴了许多古老的Shell脚本,并且因为过度使用难懂的符号而声名狼藉,这使得人们几乎无法从Google搜索到想要的语法知识。Perl作为一门脚本语言非常适合用作胶水语言,将其他脚本和程序连接到一起。Perl非常擅长处理和生成文本数据,同时也具有高度可移植性和良好的社区支持,使其成为一门应用广泛的脚本语言。Perl的设计哲学是“每个问题都有不止一种解决方法”(TMTOWTDI),而Python的设计哲学“每个问题最好只有唯一一个显而易见的解决方法”与之截然相反。 Perl有时令人厌恶,不过也有一些很棒的语言特性,就这一点上,Perl和其他编程语言是一样的。 这篇文章旨在提供知识,而不是为Perl做宣传,目标人群是(比如我自己):
这篇文档会尽可能精简,而包含的每条信息都是必要的。 序言
Hello worldPerl脚本是带有 下面是 use strict; use warnings; print "Hello world"; Perl脚本由Perl解释器解释执行, perl helloworld.pl [arg0 [arg1 [arg2 ...]]] 有几点要特别提一下:Perl的语法非常宽容,它允许你写出有歧义的或者有不可预期行为的代码。我不会去解释这些诡异的行为是什么样的,因为你最好避开它们。避免这种情况的方法是在你写的每个Perl脚本或者模块的开头加上 分号 变量Perl的变量有三种类型:标量(scalar)、数组(array)和哈希(hashes)(译者注:下文会继续使用英文原文scalar、array和hash),每种类型都有属于自己的符号:分别是 Scalar变量一个scalar变量能包含:
my $undef = undef; print $undef; # 打印空字符串"",并且抛出一个警告 # 隐式的undef(译者注:未初始化的变量初值默认为undef): my $undef2; print $undef2; # 打印"",并且抛出完全一样的警告 my $num = 4040.5; print $num; # "4040.5" my $string = "world"; print $string; # "world" (稍后会详细说明“引用”。) 用 print "Hello ".$string; # "Hello world" “布尔类型”(“Boolean”)Perl没有内置的布尔类型。
Perl的文档中反复强调函数在某些情况下返回“true”或者“false”。实际上,当一个函数声称它返回“true”,返回值往往是 弱类型无法判定一个scalar包含的是一个数值还是字符串。更准确的来说,我们没有必要知道这个信息。一个scalar按照数值还是字符串的方式参与运算,是完全取决于运算符的。因此,像字符串一样使用的时候,scalar就按字符串的方式参与运算,而像数值一样使用的时候,scalar就按照数值的方式参与运算(如果无法转换成数值则会抛出一个警告): my $str1 = "4G"; my $str2 = "4H"; print $str1 . $str2; # "4G4H" print $str1 + $str2; # "8" 并且抛出两个警告 print $str1 eq $str2; # "" (空字符串,也就是false) print $str1 == $str2; # "1" 并且抛出两个警告 # 经典错误 print "yes" == "no"; # "1" 并且抛出两个警告,按数值方式参与运算,两边求值结果都是0 教训是应该总是在恰当的情况下使用正确的运算符,对于比较数值和字符串有两套不同的运算符: # 数值运算符: <, >, <=, >=, ==, !=, <=>, +, * # 字符串运算符: lt, gt, le, ge, eq, ne, cmp, ., x Array变量Array变量是包含一个scalar列表的、由从0开始的整形数为下标存取的变量。在Python里被称为list,而在PHP里被称为array。数组可以用一个圆括号包围的scalar列表来声明(译者注:原文declaration,而这里实际表达的含义应为“初始化”,而不是对于变量标识符的声明,下同): my @array = ( "print", "these", "strings", "out", "for", "me", # 末尾多余的逗号语法上是允许的 ); 你必须要使用美元符号来存取array中的值,因为取到的值是一个scalar而非array: print $array[0]; # "print" print $array[1]; # "these" print $array[2]; # "strings" print $array[3]; # "out" print $array[4]; # "for" print $array[5]; # "me" print $array[6]; # 返回undef,打印""并且抛出一个警告 你也可以使用负数作为下标,这样就可以从末尾开始往前取某个元素: print $array[-1]; # "me" print $array[-2]; # "for" print $array[-3]; # "out" print $array[-4]; # "strings" print $array[-5]; # "these" print $array[-6]; # "print" print $array[-7]; # 返回undef,打印""并且抛出一个警告 同时存在scalar变量 取得array的长度 print "This array has ".(scalar @array)."elements"; # "This array has 6 elements" print "The last populated index is ".$#array; # "The last populated index is 5" 调用Perl脚本时使用的参数列表被保存在内置的array变量 变量可以被插入到字符串中被求值: print "Hello $string"; # "Hello world" print "@array"; # "print these strings out for me" 小心。也许有一点你会把某个人的email地址放在一个字符串里,比如 print "Hello \$string"; # "Hello $string" print 'Hello $string'; # "Hello $string" print "\@array"; # "@array" print '@array'; # "@array" Hash变量Hash变量是包含一个scalar列表的、由字符串为下标存取的变量。在Python中被称为dictionary,而在PHP中被称为array。 my %scientists = ( "Newton" => "Isaac", "Einstein" => "Albert", "Darwin" => "Charles", ); 请注意这个声明与array何其相似。事实上,这个双箭头符号 与array一样,你也需要用美元符号来存取hash中的值,因为取到的值是scalar而非hash: print $scientists{"Newton"}; # "Isaac" print $scientists{"Einstein"}; # "Albert" print $scientists{"Darwin"}; # "Charles" print $scientists{"Dyson"}; # 返回undef,打印""并且抛出一个警告 注意在这里使用的花括号。同样的,同时存在scalar变量 你可以将一个hash转换为两倍数量元素的array,原先hash中的键和值在转换后的array中交替出现(反向的转换也同样简单): my @scientists = %scientists; 然而有一点与array不同,hash中的键没有特定的保存顺序,而是以一种比较高效的方式进行存储。因此,需要注意转换后的array会将hash中的键值对重新排列次序: print "@scientists"; # 输出可能是"Einstein Albert Darwin Charles Newton Isaac" 回顾一下,我们使用方括号来取array中的值,而使用花括号来取hash中的值。方括号是一个有效的数值运算符,而花括号是一个有效的字符串运算符,因此事实上,作为下标的值是数值还是字符串类型其实并不重要(译者注:正如前文所提到的,scalar以什么方式参与运算取决于运算符): my $data = "orange"; my @data = ("purple"); my %data = ( "0" => "blue"); print $data; # "orange" print $data[0]; # "purple" print $data["0"]; # "purple" print $data{0}; # "blue" print $data{"0"}; # "blue" 列表(Lists)Perl中的列表与array和hash都不一样。你已经见过一些列表了: ( "print", "these", "strings", "out", "for", "me", ) ( "Newton" => "Isaac", "Einstein" => "Albert", "Darwin" => "Charles", ) 列表不是一个变量列表是一个暂存的值,可以被赋值到一个array或者hash变量,这就是为什么声明array和hash的语法竟完全一样。在许多情况下“列表”和“array”这两个词可以混用,而在同样多的情况下,列表和array表现出微妙的区别,并且具有极其容易混淆的行为。 好的,回想一下 ("one", 1, "three", 3, "five", 5) ("one" => 1, "three" => 3, "five" => 5) 使用 () 这里甚至没有任何变量类型的提示,这个列表可以用来声明一个空array或者空hash,而作为 my @array = ( "apples", "bananas", ( "inner", "list", "several", "entries", ), "cherries", ); Perl无法知道 print $array[0]; # "apples" print $array[1]; # "bananas" print $array[2]; # "inner" print $array[3]; # "list" print $array[4]; # "several" print $array[5]; # "entries" print $array[6]; # "cherries" 即使使用fat comma也会是同样的情况: my %hash = ( "beer" => "good", "bananas" => ( "green" => "wait", "yellow" => "eat", ), ); # 上面的代码会抛出一个警告,因为我们尝试用7个元素的列表来初始化这个hash print $hash{"beer"}; # "good" print $hash{"bananas"}; # "green" print $hash{"wait"}; # "yellow"; print $hash{"eat"}; # undef,因此打印""并且抛出一个警告 当然,这倒让连接数组变得简单了: my @bones = ("humerus", ("jaw", "skull"), "tibia"); my @fingers = ("thumb", "index", "middle", "ring", "little"); my @parts = (@bones, @fingers, ("foot", "toes"), "eyeball", "knuckle"); print @parts; 稍后会有更多关于这个问题的说明。 上下文Perl最独特的特性在于它的代码对于上下文是敏感的。每个Perl的表达式要么在scalar上下文中求值,要么在列表上下文中求值,取决于此处期望产生一个scalar还是列表。许多Perl表达式和内置函数在不同的求值上下文中的行为大相径庭。 Scalar的赋值例如 my $scalar = "Mendeleev"; Array或者hash的赋值例如 my @array = ("Alpha", "Beta", "Gamma", "Pie"); my %hash = ("Alpha" => "Beta", "Gamma" => "Pie"); 到目前为止还没什么特别的。 在列表上下文中求值的scalar表达式会被转换成含有一个元素的列表: my @array = "Mendeleev"; # 与'my @array = ("Mendeleev");'等价 在scalar上下文中求值的列表表达式会返回列表中的最后一个scalar: my $scalar = ("Alpha", "Beta", "Gamma", "Pie"); # $scalar的值现在是"Pie" 在scalar上下文中求值的array(还记得array和列表不同吗?)表达式返回该数组的长度: my @array = ("Alpha", "Beta", "Gamma", "Pie"); my $scalar = @array; # $scalar的值现在是4
my @array = ("Alpha", "Beta", "Goo"); my $scalar = "-X-"; print @array; # "AlphaBetaGoo"; print $scalar, @array, 98; # "-X-AlphaBetaGoo98"; 你可以用内置函数 即使子过程要在scalar上下文进行求值,语法上也没有规定必须要返回一个scalar,就像我们看到的,Perl完全可以为你捏造一个需要的结果。 引用和嵌套数据结构列表无法包含列表作为其元素,array也同样无法包含其他array和hash作为其元素,它们只能包含scalar。看看我们尝试下面的做法会发生什么: my @outer = ("Sun", "Mercury", "Venus", undef, "Mars"); my @inner = ("Earth", "Moon"); $outer[3] = @inner; print $outer[3]; # "2"
然而,scalar变量可以包含任何变量的引用,包括array和hash。在Perl中,复杂的数据结构就是这样被构造出来的。 我们用反斜杠来创建一个引用。 my $colour = "Indigo"; my $scalarRef = \$colour; 如果你能够使用某个变量名,你可以加一些花括号,把一个变量的引用放进去。 print $colour; # "Indigo" print $scalarRef; # 输出可能是 "SCALAR(0x182c180)" print ${ $scalarRef }; # "Indigo" 如果结果没有歧义的话,你甚至可以直接省略掉花括号: print $$scalarRef; # "Indigo" 如果是一个对array或者hash的引用,你可以用花括号或者更加风靡的箭头运算符 my @colours = ("Red", "Orange", "Yellow", "Green", "Blue"); my $arrayRef = \@colours; print $colours[0]; # 直接访问array元素 print ${ $arrayRef }[0]; # 通过引用访问array元素 print $arrayRef->[0]; # 与上一句等价 my %atomicWeights = ("Hydrogen" => 1.008, "Helium" => 4.003, "Manganese" => 54.94); my $hashRef = \%atomicWeights; print $atomicWeights{"Helium"}; # 直接访问hash元素 print ${ $hashRef }{"Helium"}; # 通过引用访问hash元素 print $hashRef->{"Helium"}; # 与上一句等价 - 这种写法相当常见 声明数据结构这里有4个例子,不过现实中最后一个最有用。 my %owner1 = ( "name" => "Santa Claus", "DOB" => "1882-12-25", ); my $owner1Ref = \%owner1; my %owner2 = ( "name" => "Mickey Mouse", "DOB" => "1928-11-18", ); my $owner2Ref = \%owner2; my @owners = ( $owner1Ref, $owner2Ref ); my $ownersRef = \@owners; my %account = ( "number" => "12345678", "opened" => "2000-01-01", "owners" => $ownersRef, ); 显然可以不用这么费劲,这段代码可以简化为: my %owner1 = ( "name" => "Santa Claus", "DOB" => "1882-12-25", ); my %owner2 = ( "name" => "Mickey Mouse", "DOB" => "1928-11-18", ); my @owners = ( \%owner1, \%owner2 ); my %account = ( "number" => "12345678", "opened" => "2000-01-01", "owners" => \@owners, ); 用不同的符号声明匿名的array和hash也是可行的。用方括号声明匿名array,而用花括号声明匿名hash,这两种方法返回的是声明的匿名数据结构的引用。看仔细了,下面的代码声明的 # 花括号表示匿名hash my $owner1Ref = { "name" => "Santa Claus", "DOB" => "1882-12-25", }; my $owner2Ref = { "name" => "Mickey Mouse", "DOB" => "1928-11-18", }; # 方括号表示匿名array my $ownersRef = [ $owner1Ref, $owner2Ref ]; my %account = ( "number" => "12345678", "opened" => "2000-01-01", "owners" => $ownersRef, ); 或者写得更加简短(这也是你真正应该用来声明复杂数据结构的方法): my %account = ( "number" => "31415926", "opened" => "3000-01-01", "owners" => [ { "name" => "Philip Fry", "DOB" => "1974-08-06", }, { "name" => "Hubert Farnsworth", "DOB" => "2841-04-09", }, ], ); 从数据结构中获取信息现在我们假设你还在折腾那个 my $ownersRef = $account{"owners"}; my @owners = @{ $ownersRef }; my $owner1Ref = $owners[0]; my %owner1 = %{ $owner1Ref }; my $owner2Ref = $owners[1]; my %owner2 = %{ $owner2Ref }; print "Account #", $account{"number"}, "\n"; print "Opened on ", $account{"opened"}, "\n"; print "Joint owners:\n"; print "\t", $owner1{"name"}, " (born ", $owner1{"DOB"}, ")\n"; print "\t", $owner2{"name"}, " (born ", $owner2{"DOB"}, ")\n"; 或者写得更简短些: my @owners = @{ $account{"owners"} }; my %owner1 = %{ $owners[0] }; my %owner2 = %{ $owners[1] }; print "Account #", $account{"number"}, "\n"; print "Opened on ", $account{"opened"}, "\n"; print "Joint owners:\n"; print "\t", $owner1{"name"}, " (born ", $owner1{"DOB"}, ")\n"; print "\t", $owner2{"name"}, " (born ", $owner2{"DOB"}, ")\n"; 或者使用引用和 my $ownersRef = $account{"owners"}; my $owner1Ref = $ownersRef->[0]; my $owner2Ref = $ownersRef->[1]; print "Account #", $account{"number"}, "\n"; print "Opened on ", $account{"opened"}, "\n"; print "Joint owners:\n"; print "\t", $owner1Ref->{"name"}, " (born ", $owner1Ref->{"DOB"}, ")\n"; print "\t", $owner2Ref->{"name"}, " (born ", $owner2Ref->{"DOB"}, ")\n"; 如果我们完全跳过那些中间值,代码看起来就是这样: print "Account #", $account{"number"}, "\n"; print "Opened on ", $account{"opened"}, "\n"; print "Joint owners:\n"; print "\t", $account{"owners"}->[0]->{"name"}, " (born ", $account{"owners"}->[0]->{"DOB"}, ")\n"; print "\t", $account{"owners"}->[1]->{"name"}, " (born ", $account{"owners"}->[1]->{"DOB"}, ")\n"; 如何用array的引用作茧自缚这个数组有5个元素: my @array1 = (1, 2, 3, 4, 5); print @array1; # "12345" 然而这个array只有1个元素(一个含有5个元素的匿名array的引用): my @array2 = [1, 2, 3, 4, 5]; print @array2; # e.g. "ARRAY(0x182c180)" 这个scalar是一个含有5个元素的匿名array的引用: my $array3Ref = [1, 2, 3, 4, 5]; print $array3Ref; # e.g. "ARRAY(0x22710c0)" print @{ $array3Ref }; # "12345" print @$array3Ref; # "12345" 条件分支
|
请发表评论