加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

2个半小时 学PERL

发布时间:2020-12-15 23:48:55 所属栏目:大数据 来源:网络整理
导读:http://qntm.org/files/perl/perl.html ? 2个半小时 学PERL Perl是一个动态的,动态类型,高级,脚本(解释)语言与PHP和Python语言很像,Perl的语法内嵌了很多古老的shell脚本工具,这是对它的混乱符号的过度使用而著名 其中大部分是不能google到的,Perl的脚
http://qntm.org/files/perl/perl.html ? 2个半小时 学PERL Perl是一个动态的,动态类型,高级,脚本(解释)语言与PHP和Python语言很像,Perl的语法内嵌了很多古老的shell脚本工具,这是对它的混乱符号的过度使用而著名 其中大部分是不能google到的,Perl的脚本语言遗产使它非常适合编写胶水代码:把其他的脚本语言串联 起来 Perl擅长处理文本数据和产生更多的文本数据。Perl是广泛的 普遍的 便携的语言。 Perl有恐惧,但也有一些可取之处。在这方面,它是像其他编程语言所创造的。 本文件的目的是提供信息,而不是福音。它是针对人群是像我这样: 1.不喜欢官方的文档专注于技术 2.学习新的项目语言最快是通过"axiom and example" 3.已经知道如何在一般条款的程序 4.不在乎Perl超出完成工作的必要 Hello world 一些小的注意点,Perl的语法是非常宽容的,它会让你一些导致模糊的不可预知的事情。 对我来说没有一点值得解释,因为你需要去避免他们。避免的方式是使用use strict; use warnings 在每个Perl脚本的开头,语句的形式是use foo 是编译 一个编译成perl.exe 分号是语句结束符;,。符号#开始评论。评论一直持续到该行的末尾。Perl没有块注释语法。 变量: Perl变量有3种类型: 标量,数组和hashes. 每个类型有自己的符号$,@,% 变量定义用my? 保持在范围内直到在块或文件结束. Scalar variables 1.undef (corresponds to None in Python,null in PHP) 2. number perl Perl不区分整数和浮点 布尔值: 为假的情况: undef number 0 string "" string "0". Perl文档一再声称,函数返回“真”或“假”值,在某些情况下。 在实践中,当一个函数被称为“真正的”通常返回返回1,当它声称要返回false通常返回空字符串,"" Weak typing 弱类型: 判断一个标量包含number 或者是字符窜是不可能的。 更确切地说,它没有必要这样做,无论是一个标量的行为像一个数字或字符串取决于使用者怎么使用。 正确的使用操作符在正确的情况下,比较number和字符窜的: # Numerical operators: ?<,?>,<=,>=,==,!=,<=>,+,* # String operators: ? ?lt,gt,le,ge,eq,ne,cmp,.,x 数组变量: 一个数组变量是有整数0开始索引的列表,数组是使用一个标量的圆括号列表声明 my @array = ( "print","these","strings","out","for","me",# trailing comma is okay ); 你可以使用dollar 符号访问数组的值,由于检索的值不是数组是标量 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]; # returns undef,prints "" and raises a warning 在标量$var和数组@var 包含一个标量进入到 $var[0]是没有冲突的。可能会读起来混乱 因此为了避免这种情况,To get an array's length: 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脚本的参数包含在内建变量@ARGV中 [oracle@dwh1 ~]$ cat 4.pl ? if ($#ARGV <0){ ? ? ? ? ? print "请输入一个表名参数"; ? print "$#ARGV is $#ARGVn"; ? ? ? ? ? exit(-1); ? ? ? }else{ ? print "$#ARGV is $#ARGVn"; ? } ? ?? [oracle@dwh1 ~]$ perl 4.pl ? 请输入一个表名参数$#ARGV is -1 ? ?? ?? $#ARGV ?参数个数减去1,0个参数减去1 就是-1 ? ?? ?? [oracle@dwh1 ~]$ perl 4.pl 1 ? $#ARGV is 0 ? 注意: 如果某天你要把某人的邮件地址放在一个字符串中,"jeff@gmail.com". 这会导致Perl去寻找一个数组@gmail 数组内插,数组内插可以有2种方式来防止: 用反斜杠转义或者使用单引号代替双引号 Hash 变量: Hash 变量是一些标量有字符窜索引 my %scientists = ( "Newton" ? => "Isaac","Einstein" => "Albert","Darwin" ? => "Charles",); 注意:HASH和数组定义是多么的相似.实际上,双箭头符号= >被称为“脂肪逗号” 因为它只是一个逗号分隔符的同义词,哈希是使用列表 用Number元素,print $scientists{"Newton"}; ? # "Isaac" print $scientists{"Einstein"}; # "Albert" print $scientists{"Darwin"}; ? # "Charles" print $scientists{"Dyson"}; ? ?# returns undef,prints "" and raises a warning 注意这里使用的括号,在标量$var和hash %var没有冲突 然而,不像数组,一个哈希键有没有潜在的秩序,因此 注意重新编排的顺序保存键值对的结果 print "@scientists"; # something like "Einstein Albert Darwin Charles Newton Isaac" 总的来说,你必须用方括号从数组中检索一个值,但你必须使用括号从散列检索值。 括号内的是有效的数值运算符和括号是有效的字符串运算符 列表 是不同于数组和HASH ( "print",) ( "Newton" ? => "Isaac",) 一个列表不是一个变量:列表是一个短暂的值可以被分配给列表或者数组。 这就是为什么声明数组和散列变量是相同的语法,有许多情况下,术语“列表”和“数组”可以互换使用,但也有些细微的不同 好吧,记住=>是伪装的 ("one",1,"three",3,"five",5) ("one" => 1,"three" => 3,"five" => 5) 使用= >暗示一个列表是一个数组的声明,其他是一个哈希定义 甚至没有暗示在这里,这个列表可以用于定义一个空的数组或者一个空的hash, Perl解释没法说明。 一旦你理解了这几个方面的Perl,你也会明白为什么下面的事实必须是真实的,列表中的值,不能嵌套 。 Perl没有办法知道("inner","list","several","entries"))是一个内部数组或内部哈希 同样的是否是真的胖逗号的使用或不: 语境: Perl最鲜明的特征是,它的代码是上下文敏感的. Perl中的每个表达式的求值在标量上下文语境或列表,依赖于是期望产生一个标量或者列表。 标量赋值比如 my $scalar = 计算表达式为scalar语境? 一个数组或者hash赋值比如my @array = or my %hash = 计算表达式在列表语境 my @array = ("Alpha","Beta","Gamma","Pie"); my %hash = ("Alpha" => "Beta","Gamma" => "Pie"); 一个标量表达式列表中默默地转换成一个单一的元素列表 my @array = "Mendeleev"; # same as 'my @array = ("Mendeleev");' 一个数组表达式计算在标量语境下返回数组的长度 my @array = ("Alpha","Pie"); my $scalar = @array; print $scalar; # "4" 一个列表表达式(列表不同于数组)在标量语境下计算返回的不是列表的长度而是列表的最后一个标量 my $scalar = ("Alpha","Pie"); print $scalar; # "Pie" print 内建函数计算所有列表语境下的参数 实际上,print 接受无限的列表参数 一个接一个的打印 这意味着它可惜直接打印数组 my @array = ("Alpha","Goo"); my $scalar = "-X-"; print @array; ? ? ? ? ? ? ?# "AlphaBetaGoo"; print $scalar,@array,98; # "-X-AlphaBetaGoo98"; References and nested data structures 引用和嵌套的数据结构 在相同的方式,列表不能包含列表作为元素 数组和HASH不能包含其他的数组和HASH作为元素。他们可以包含标量。 my @outer = ("Sun","Mercury","Venus",undef,"Mars"); my @inner = ("Earth","Moon"); $outer[3] = @inner; print $outer[3]; # "2" $outer[3]是一个标量,因此它需要一个标量值。当你给数组赋值像@inner? @inner 被当做标量语境。这好比是给标量赋值数组,表示数组的长度 然而,一个标量变量可能包含任何一个变量的引用,可能是数组变量或者hash变量 Perl有很多复杂的数据结构 引用的创建是使用 my $colour ? ?= "Indigo"; my $scalarRef = $colour; 任何时候你会使用一个变量的名字,你可以用大括号代替,在大括号下。 print $colour; ? ? ? ? # "Indigo" print $scalarRef; ? ? ?# e.g. "SCALAR(0x182c180)" print ${ $scalarRef }; # "Indigo" 你也可以省略大括号: print $$scalarRef; # "Indigo" 如果你引用的是一个数组或者HASH变量,你可以使用大括号取得数据 或者使用更加普通的箭头符号-> 数组引用: my @colours = ("Red","Orange","Yellow","Green","Blue"); my $arrayRef = @colours; print $colours[0]; ? ? ? # direct array access print ${ $arrayRef }[0]; # use the reference to get to the array print $arrayRef->[0]; ? ?# exactly the same thing HASH引用: my %atomicWeights = ("Hydrogen" => 1.008,"Helium" => 4.003,"Manganese" => 54.94); my $hashRef = %atomicWeights; print $atomicWeights{"Helium"}; # direct hash access print ${ $hashRef }{"Helium"}; ?# use a reference to get to the hash print $hashRef->{"Helium"}; ? ? # exactly the same thing - this is very common 定义一个数据结构 这里有4个例子,最后一个是最有用的 它也可以声明匿名数组和hash 使用不同的符号,使用方括号用于匿名散列匿名数组的括号. 每种情况的返回值是匿名数据结构的引用。 获取数据结构的信息: 现在,假设你仍旧有%account 条件语句: if ... elsif ... else ... 在这里,没有惊喜,除了elsif拼写 my $word = "antidisestablishmentarianism"; my $strlen = length $word; if($strlen >= 15) { print "'",$word,"' is a very long word"; } elsif(10 <= $strlen && $strlen < 15) { print "'","' is a medium-length word"; } else { print "'","' is a short word"; } Perl提供了简短的if条件语句 print "'","' is actually enormous" if $strlen >= 20; unless ... else ... my $temperature = 20; unless($temperature > 30) { print $temperature," degrees Celsius is not very hot"; } else { print $temperature," degrees Celsius is actually pretty hot"; } This,by comparison,is highly recommended because it is so easy to read: print "Oh no it's too cold" unless $temperature > 15; 三元运算符: 运算符 ?: ?允许简单的if语句被嵌入在一个声明中,本规范使用的单/复数形式 my $gain = 48; print "You gained ",$gain," ",($gain == 1 ? "experience point" : "experience points"),? "!"; 循环: Perl有传统的while 循环: my @array = qw/1 2 3 4 5 6/; my $i = 0; while($i < scalar @array) { print "$i : ?$array[$i]n"; $i++; } Perl also offers the until keyword: my @array = qw/1 2 3 4 5 6/; my $i = 0; until($i >= scalar @array) { print "$i: $array[$i]n"; $i++; } 基本的C模式的循环都可以,注意当我们把my放到for语句里时,定义的$i只在for循环里有效 for(my $i = 0; $i < 10; $i++) { print "$in"; } # $i has ceased to exist here,which is much tidier. print "2-----$in"; 此时$i不存在了 for循环被认为是过时了,应该尽可能的避免,注意不像PHP for和foreach关键字是同义词,foreach my $string ( @array ) { print $string; } 范围操作符,创建一个匿名数组 foreach my $i ( 0 .. $#array ) { print $i,": ",$array[$i]; } 你不能遍历一个hash数组,然而你可以遍历键值。使用键来访问Hash数组的元素 foreach my $key (keys %scientists) { print $key,$scientists{$key}; } Hash没有潜在的顺序,使用sort 排序键值 foreach my $key (sort keys %scientists) { print $key,$scientists{$key}; } 如果你不提供一个明确的迭代器,perl会使用$_ foreach ( @array ) { print $_; } 循环控制: next和last 可以空余控制循环,在其他语言中它们被当做continue和break. 我们还可以使用label,按照惯例,标签都写在allcapitals. 操作数组的函数 数组的修改: 我们使用@stack来证明: my @stack = ("Fred","Eileen","Denise","Charlie"); print @stack; # "FredEileenDeniseCharlie" pop提取并返回数组的最后一个元素。 print pop @stack; # "Charlie" print @stack; ? ? # "FredEileenDenise" push 数组尾部追加元素 push @stack,"Bob","Alice"; print @stack; # "FredEileenDeniseBobAlice" shift 提取并返回数组的第一个元素 print shift @stack; # "Fred" print @stack; ? ? ? # "EileenDeniseBobAlice" unshift ? 在数组开头插入元素 unshift @stack,"Hank","Grace"; print @stack; # "HankGraceEileenDeniseBobAlice" pop,push,shift and unshift 都是特殊的剪切操作 从老的数组创建新的数组 join 函数连接多个字符串为一个字符窜: my @elements = ("Antimony","Arsenic","Aluminum","Selenium"); print "1------@elementsn"; print join ("perl",@elements); D:perl>perl 4.pl 1------Antimony Arsenic Aluminum Selenium AntimonyperlArsenicperlAluminumperlSelenium 列表中,reverse函数返回颠倒顺序的数组。在标量环境中,print reverse("Hello","World"); ? ? ? ?# "WorldHello" print reverse("HelloWorld"); ? ? ? ? ? ?# "HelloWorld" print scalar reverse("HelloWorld"); ? ? # "dlroWolleH" print scalar reverse("Hello","World"); # "dlroWolleH map函数把数组作为输入处理每个数组的元素,产生一个新的数组。 my @capitals = ("Baton Rouge","Indianapolis","Columbus","Montgomery","Helena",? "Denver","Boise"); print join ",",map { uc $_ } @capitals; # "BATON ROUGE,INDIANAPOLIS,COLUMBUS,MONTGOMERY,HELENA,DENVER,BOISE" grep 函数传入数组后经过过滤,作为数组输出,类似于map函数。 print join ",grep { length $_ == 6 } @capitals; # "Helena,Denver" 显然,结果数组的长度是成功匹配的数量,你可以使用grep 确认数组是否包含某个元素。 print scalar grep { $_ eq "Columbus" } @capitals; # "1" grep和map可以组合成列表解析,非常强大的特性有别于其他语言 my @elevations = (19,2,100,98,1056); my @b = sort @elevations; print "@b is @bn"; D:perl>perl 5.pl @b is 1 100 100 1056 19 2 3 98 然而,类似于grep 和 map,你可以提供一些你自己的代码。 排序是进行了一系列比较两个元素之间的。 内建函数 现在你已经看到了至少十几个内置函数print,sort,map,grep,keys,scalar 内建函数是PERL功能的加强 用户定义的子程序: 子程序用sub关键字定义,和内置函数对比上,用户定义的字程序通常接收标量的列表。 列表可能只包含一个元素,或者为空 子程序的参数存储在@_中 sub hyphenate { ? # Extract the first argument from the array,ignore everything else ? my $word = shift @_; ? # An overly clever list comprehension ? $word = join "-",map { substr $word,$_,1 } (0 .. (length $word) - 1); ? return $word; } print hyphenate("exterminate"); # "e-x-t-e-r-m-i-n-a-t-e" 这句话解释的是你子例程中内部定义的变量视作用在当前子例程的代码块里,它是最初的独立的变量跟 你外部的变量没任何关系 my $x = 7; sub reassign { ? $_[0] = 42; } reassign($x); print $x; # "42" $_[0] 是$x的引用 在C语言里事变量的COPY 这个高速我们子程序的内部,你可能要经常在你和他们打交道前 解决这种争论。 解决争论 有多种方法来解决@_,相比其他有些是优秀的。 子程序left_pad 返回值: 像其他的表达式,子程序调用取决于上下文的表现,你可以使用wantarray function去检测 子程序苹果上下文,返回结果的适当的上下文. 如果你已经知道以下非Perl相关的事实 文件和文件句柄: 一个文件句柄基本上是一个特定文件的引用。使用open 打开一个标量指向文件句柄 my $f = "text.txt"; my $result = open my $fh,"<",$f; if(!$result) { die "Couldn't open '".$f."' for reading because: ".$!; } 如果成功,open返回一个真值,否则,返回错误信息保存到内建变量$!。 注意,在打开的参数需要括号 把文本读到文件句柄,使用内建函数readline. ?readline 返回文本的所有行,读到一行的最后 或者读到文件最后 会返回undef while(1) { my $line = readline $fh; last unless defined $line; # process the line... } 截取换行符 chomp $line; 正则表达式: 正则表达式出现在很多语言中相比Perl. Perl的正则表达式语法的核心基本上哪儿都一样 Perl的正则表达式的能力充满极为复杂和难以理解 匹配操作符 使用 =~ m// In scalar context,=~ m// returns true on success,false on? failure. my $string = "Hello world"; if($string =~ m/(w+)s+(w+)/) { print "success"; } 执行子匹配的括号,当一个操作成功的匹配,子匹配的被塞进内建变量$1,$2,$3 my $string = "Hello world"; if($string =~ m/(w+)s+(w+)/) { print "success"; } print "$1 is $1n"; print "$2 is $2n"; D:perl>perl 7.pl success$1 is Hello $2 is world w+ ?[a-zA-Z0-9]+ 语法一样 ?? s+ ? [ntrf]+ 一样 在这个列表中: =~ m// returns $1,... as a list. my $string = "colourless green ideas sleep furiously"; my @matches = $string =~ m/(w+)s+((w+)s+(w+))s+(w+)s+(w+)/; Substitution operations are performed using =~ s///. 替换操作符 my $string = "Good morning world"; $string =~ s/world/Vietnam/; print $string; # "Good morning Vietnam" The /g flag indicates "group match". 在标量语境,每个=~ m//g,逐个匹配,成功返回true ?你可以访问$1 /i 不区分大小写 模块和包 在Perl里 模块和包是不同的东西 一个模块是一个.pm文件,一个模块类似一个Perl脚本 因为一个模块执行从上到下加载,你需要返回一个真值,最后说明加载成功 use strict; use warnings; sub zombify { my $word = shift @_; $word =~ s/[aeiou]/r/g; return $word; } return 1; 因此,Perl解释器可以找到他们,包含PERL模块的目录必须设置在环境变量PERL5LIB。 列出根目录包含的模块,不列出模块目录或者模块本身: set PERL5LIB=C:foobarbaz;%PERL5LIB% or export PERL5LIB=/foo/bar/baz:$PERL5LIB 当Perl模块被创建而且,perl知道如何找到它,你可以使用内建函数require去查找和执行Perl脚本。 比如,calling require Demo::StringUtils 使Perl搜索PERL5LIB中列出的目录,寻找一个Demo/StringUtils.pm文件。 当模块被执行后,子程序定义变的可用,use strict; use warnings; require Demo::StringUtils; print zombify("i want brains"); # "r wrnt brrrns" Note the use of the double colon :: as a directory separator 注意 ::作为目录分割符号 那么问题来了.如果一个main.pl里包含了很多的require calls, 每个加载的模块包含更多的require calls,追踪原始的子程序zombify()变的困难 解决办法是使用包 Packages: 一个包就是个名字空间 包含子函数的定义。 任何子程序声明隐式声明当前包内的 在执行开始,你在main包里,但是你可以切换包使用内建函数 package use strict; use warnings; sub subroutine { print "universe"; } package Food::Potatoes; # no collision: sub subroutine { print "kingedward"; } Note the use of the double colon :: as a namespace separator. 注意::表示名字空间分隔符 任何时候你调用子函数,你隐式的调用了包含子函数的包。 另外,你可以明确地提供一个包。如果我们继续上面的脚本会发生什么: subroutine(); ? ? ? ? ? ? ? ? # "kingedward" main::subroutine(); ? ? ? ? ? # "universe" Food::Potatoes::subroutine(); # "kingedward" 现在读的仔细一点: 包和模块是两个完全单独的功能在Perl语言里,他们都使用双冒号分隔 它可以在脚本或者模块中多次的切换包,它可以在多个文件中的多个位置使用相同的包装声明, 调用require Foo::Bar不需要寻找和加载包名为Foo::Bar定义,也不需要加载 Foo::Bar namespace里的子函数 调用 require Foo::Bar 仅仅加载了 Foo/Bar.pm文件 同样的,一个子函数 call Baz::Qux::processThis() 不需要定义在 Baz/Qux.pm里 它可以是定义在其他地方 分离这两个概念是一个Perl的最愚蠢的特征,并把它们作为单独的概念总是导致混乱,疯狂的代码。幸 运的是,Perl程序员多数服从以下两个规律: 1.1个Perl script (.pl file) 总是必须包含0个包定义 2.一个Perl模块包含一个包定义,对应它的名字和位置 面向对象: Perl是不是面向对象的编程语言的一个重要 Perl的面向对象的能力进行嫁接后的事实 一个对象可以简单的理解为引用,这恰好知道引用所属的类别 告诉一个引用,其所指属于一类 使用bless 找出引用属于什么类? 一种方法是一个简单的子程序,将一个对象作为一个参数 对象的方法调用使用 $obj->method()

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读