Perl精华教程
发布时间:2020-12-16 00:09:04 所属栏目:大数据 来源:网络整理
导读:Perl教程 第一讲 1、一个最简单的Perl程序? 这里是我们开始的一个基本的perl程序: #!/usr/local/bin/perl # # Program to do the obvious print 'Hello world.';# Print a message 我们将对其中的每个部分进行讨论。 第一行: 每个perl程序的第一行都是: -
Perl教程
第一讲 1、一个最简单的Perl程序? 这里是我们开始的一个基本的perl程序: #!/usr/local/bin/perl # # Program to do the obvious print 'Hello world.';# Print a message 我们将对其中的每个部分进行讨论。 第一行: 每个perl程序的第一行都是: - 虽然随着系统的不同而不同。这行告诉机器当文件执行时该怎么做(即告诉它通过Perl运行这个文件)。? 目 录? 1、一个最简单的Perl程序 2、运行程序 3、标量? 第二讲 1、数组变量 2、文件处理 3、控制结构? 第三讲 1、条件语句 2、字符串匹配 3、替换和翻译? 第四讲 1、Split 2、关联数组 3、子过程? 其它网上教程-->> 注释和语句: 用#符号可以在程序中插入注释,并且从#开始到这行结尾都被忽略(除了第一行)。把注释扩展到几行的唯一办法是在每行前都用#符号。 Perl中的语句必须在结尾加一个分号,象上面程序中最后一行那样。 简单的打印: print函数输出一些信息。在上面的例子中它打印出字符串Hello world,当然这行也以分号结束。 你可能会发现上面的程序会产生一个有点意想不到的结果,那么就让我们运行它吧。 用文本编辑器敲入这个例子程序,然后保存之。Emacs是一个很好的编辑器,但是你可以使用任何习惯的文本编辑器。 然后用下面的命令使这个文件可执行。 chmod u+x progname 在UNIX提示符下,progname是程序的文件名。现在可以运行这个程序 - 在提示符下运行下面任何一种命令: perl progname ./progname progname 如果有错误,将会得到错误信息,或者什么也得不到。可以用warning参数运行程序: perl -w progname 这会在试图执行程序前显示警告和其它帮助信息。用调试器运行程序可以使用命令: perl -d progname 当执行程序时,Perl首先编译之,然后执行编译后的版本。于是在经过编辑程序后的短暂停顿后,这个程序会运行得很快。 2、运行程序 当执行程序时,Perl首先编译之,然后执行编译后的版本。于是在经过编辑程序后的短暂停顿后,这个程序会运行得很快。>> 3、标量 Perl中最基本的变量是标量。标量可以是字符串或数字,而且字符串和数字可以互换。例如,语句 $priority = 9; 设置标量$priority为9,但是也可以设置它为字符串:$priority = 'high'; Perl也接受以字符串表示的数字,如下: $priority = '9'; $default = '0009'; 而且可以接受算术和其它操作。 一般来说,变量由数字、字母和下划线组成,但是不能以数字开始,而且$_是一个特殊变量,我们以后会提到。同时,Perl是大小写敏感的,所以$a和$A是不同的变量。 操作符和赋值语句: Perl使用所有的C常用的操作符: $a = 1 + 2;# Add 1 and 2 and store in $a $a = 3 - 4;# Subtract 4 from 3 and store in $a $a = 5 * 6;# Multiply 5 and 6 $a = 7 / 8;# Divide 7 by 8 to give 0.875 $a = 9 ** 10;# Nine to the power of 10 $a = 5 % 2;# Remainder of 5 divided by 2 ++$a;# Increment $a and then return it $a++;# Return $a and then increment it --$a;# Decrement $a and then return it $a--;# Return $a and then decrement it 对于字符串,Perl有自己的操作符: $a = $b . $c;# Concatenate $b and $c $a = $b x $c;# $b repeated $c times Perl的赋值语句包括: $a = $b;# Assign $b to $a $a += $b;# Add $b to $a $a -= $b;# Subtract $b from $a $a .= $b;# Append $b onto $a 其它的操作符可以在perlop手册页中找到,在提示符后敲入man perlop。 互操作性: 下面的代码用串联打印apples and pears: $a = 'apples'; $b = 'pears'; print $a.' and '.$b; 最后的打印语句中应该只包含一个字符串,但是: print '$a and $b'; 的结果为$a and $b,不是我们所期望的。 不过我们可以用双引号代替单引号: print "$a and $b"; 双引号强迫任何代码的互操作,其它可以互操作的代码包括特殊符号如换行(/n)和制表符(/t)。 1、数组变量? 数组变量是标量的集合。数组变量与标量有相同的形式,除了其前缀为@符号。下面的语句把三个元素赋给数组变量@food,把两个元素赋给数组变量@music。 数组通过以0开始的索引进行访问,方括号内为索引值。表达式 $food[2]返回的结果为ells。注意上式中为$,而不是@,因为其引用的是一个标量。? 数组赋值? 在Perl中,相同的表达式在不同的上下文中会产生不同的结果。下面的第一个赋值语句引用了@music变量,所以结果与第二个赋值语句相同。 这也是把元素加入数组的一种方式。一种更简洁的把元素加入数组的方式是:? push(@food,"eggs"); - 把eggs推入数组@food的结尾。把两个或更多元素推入数组可以用下面方式中的一种: push函数返回新的列表的长度。 可以用pop函数移去一个列表中的最后一个元素,然后返回这个元素。在最初的列表中,pop函数返回eels,然后@food中有两个元素: $grub = pop(@food); # Now $grub = "eels" 也可以把数组赋给一个标量。通常上下文是很重要的。$f=@food;得到@food的长度,但是$f="@food";把列表转换成以空格隔开每个元素的字符串。通过改变特殊变量$"的值可以把空格用其它任何字符串代替。这个变量只是Perl中很多特殊变量中的一个,它们中的很多都有奇怪的名字。 数组也可以用来为多个标量进行赋值: ($a,$b) = ($c,$d);# Same as $a=$c; $b=$d; # items of @food. # @somefood is a list of the # others. (@somefood,$a) = @food;# @somefood is @food and # $a is undefined. 最后一个赋值语句的发生是因为数组是贪婪的,@somefood会吞掉@food中的任何值。因此应尽量避免这种方式。 最后,你可能想知道列表中最后一个元素的索引值,可以用这个表达式:$#food。 打印数组: 既然上下文很重要,就不要奇怪下面的表达式产生不同的结果: print @food;# By itself print "@food";# Embedded in double quotes print @food."";# In a scalar context 2、文件处理 下面是一个简单的perl程序,与UNIX中cat命令对某个文件的操作相同。 # Program to open the password file,read it in, # print it,and close it again. $file = '/etc/passwd';# Name the file open(INFO,$file);# Open the file @lines = <INFO>;# Read it into an array close(INFO);# Close the file print @lines;# Print the array open函数打开一个文件并进行读操作。第一个参数filehandle是指向文件的句柄。第二个参数为被打开的文件的文件名。如果文件名以被引号包围的形式给出,那么它只被从字面意义上引用,而没有shell解释。 因此表达式'~/notes/todolist'不会被成功地翻译。如果希望得到shell解释,可以使用尖括号:即使用<~/notes/todolist>。 close函数告诉Perl关闭被打开的文件。 open语句也可以对文件进行输出和附加操作。可以在文件名前加>进行输出操作,用>>进行附加操作: 如果想在一个已经打开的文件中打印信息,可以用带参数的打印语句。把一个字符串打印到一个用INFO句柄打开的文件中可以使用 print INFO "This line goes to the file./n"; 可以用下面的语句打开标准输入(通常为键盘)和标准输出(通常为屏幕): 在上面的程序中从一个文件中读取信息。这个文件是INFO,Perl用尖括号对它进行读操作。因此语句 @lines=<INFO>; 把文件中的所有信息读入数组@lines中。如果用标量$lines,则只读第一行。在这两种情况下,每行都以换行符结束。 3、控制结构 Perl支持很多种与C类似的控制结构,但是也与Pascal很相似。下面我们分别对着这些结构进行讨论。 foreach Perl使用foreach结构对数组或其它列表结构中的每行进行操作: foreach $morsel (@food)# Visit each item in turn # and call it $morsel { print "$morsel/n";# Print the item print "Yum yum/n";# That was nice } 每次的操作过程被包围在花括号内。程序块中的$morsel第一次被赋予@food数组中的第一个值,然后被赋予数组的第二个值,依次类推。如果@food是空的,那么程序块将不会被执行。 判断 判断是检验表达式结果是真是假的一种结构。在Perl中,任何非0数字和非空字符串被看作真。数字0、0字符串和空字符串被看作假。下面是一些基于数字和字符串的判断: $a == $b# Is $a numerically equal to $b? # Beware: Don't use the = operator. $a != $b# Is $a numerically unequal to $b? $a eq $b# Is $a string-equal to $b? $a ne $b# Is $a string-unequal to $b? 也可以用逻辑与、或、非: ($a && $b)# Is $a and $b true? ($a || $b)# Is either $a or $b true? !($a)# is $a false? for Perl的for结构与C的类似: for (initialise; test; inc) first_action; second_action; etc 语句initialise被首先执行,然后当test为真时程序块被执行。程序块每执行一次,inc发生一次。下面是一个循环打印数字0到9的循环: for ($i = 0; $i < 10; ++$i)# Start with $i = 1 # Do it while $i < 10 # Increment $i before repeating print "$i/n"; while和until 下面是一个从键盘读输入,知道口令正确为止的程序: print "Password? ";# Ask for input $a = <STDIN>;# Get input chop $a;# Remove the newline at end while ($a ne "fred")# While input is wrong... print "sorry. Again? ";# Ask again $a = <STDIN>;# Get input again chop $a;# Chop off newline again 当键盘输入与口令不同时花括号内的程序块被执行。while结构很清晰,但有几点要注意:第一,我们可以从标准输入读入信息,而不用打开文件。第二,当口令被输入时,$a被赋予包括换行符在结尾的值。chop函数删除字符串的最后一个字符,这里是换行符。 until也可以执行相同的工作。程序块被反复执行,直到表达式为真。 另一种方式是把while或until放在程序块的后面。这要求do放在程序块的开始处,而判断在结尾处。这样程序可以这样写: do "Password? ";# Ask for input chop $a;# Chop off newline while ($a ne "fred")# Redo while wrong input 1、条件语句? Perl当然也支持if/then/else语句,下面是一个例子: if ($a) print "The string is not empty/n"; else print "The string is empty/n"; 记住,空字符串被认为是false,如果$a是字符串"0",结果将是"empty"。? 条件语句中也可以使用elsif:? if (!$a)# The ! is the not operator elsif (length($a) == 1)# If above fails,try this print "The string has one character/n"; elsif (length($a) == 2)# If that fails,51); font-family:Arial; font-size:14px; line-height:26px">print "The string has two characters/n"; else# Now,everything has failed print "The string has lots of characters/n"; 注意:elsif中确实缺一个"e"。 2、字符串匹配 Perl的最有用的特征之一是它的强大的字符串处理能力。其中的核心是被很多其它UNIX工具使用的规则表达式(regular expression - RE)。 规则表达式 规则表达式包含在斜线内,匹配通过=~操作符进行。如果字符串the出现在变量$sentence中,则下面的表达式为真: $sentence =~ /the/ RE是大小写敏感的,所以如果 $sentence = "The quick brown fox"; 那么上面的匹配结果为false。操作符!~用在“非匹配”时,在上面的例子中 $sentence !~ /the/ 是真,因为字符串the没有出现在$sentence中。 特殊变量$_ 在条件语句 if ($sentence =~ /under/) print "We're talking about rugby/n"; 中,如果我们有下面两个表达式中的一个: $sentence = "Up and under"; $sentence = "Best winkles in Sunderland"; 将打印出一条信息。 但是如果我们把这个句子赋值给特殊变量$_,用起来会更容易些。如果这样,我们可以避免使用匹配和非匹配操作符,上面的例子可以写成: if (/under/) $_变量是很多Perl操作的缺省变量,经常被使用。 其它的RE 在RE中有大量的特殊字符,既使它们功能强大,又使它们看起来很复杂。最好在用RE时慢慢来,对它们的使用是一种艺术。 下面是一些特殊的RE字符和它们的意义: . # Any single character except a newline ^ # The beginning of the line or string $ # The end of the line or string * # Zero or more of the last character + # One or more of the last character ? # Zero or one of the last character 下面是一些匹配的例子,在使用时应加上/.../: t.e # t followed by anthing followed by e # This will match the # tre # tle # but not te # tale ^f # f at the beginning of a line ^ftp # ftp at the beginning of a line e$ # e at the end of a line tle$ # tle at the end of a line und* # un followed by zero or more d characters # This will match un # und # undd # unddd (etc) .* # Any string without a newline. This is because # the . matches anything except a newline and # the * means zero or more of these. ^$ # A line with nothing in it. 还有更多的用法。方括号用来匹配其中的任何一个字符。在方括号中"-"表明"between","^"表示"not": [qjk] # Either q or j or k [^qjk] # Neither q nor j nor k [a-z] # Anything from a to z inclusive [^a-z] # No lower case letters [a-zA-Z] # Any letter [a-z]+ # Any non-zero sequence of lower case letters 上面提到的已经基本够用了,下面介绍的只做参考: 竖线"|"表示"or",括号(...)可以进行集合: jelly|cream # Either jelly or cream (eg|le)gs # Either eggs or legs (da)+ # Either da or dada or dadada or... 下面是一些其它的特殊字符: /n # A newline /t # A tab /w # Any alphanumeric (word) character. # The same as [a-zA-Z0-9_] /W # Any non-word character. # The same as [^a-zA-Z0-9_] /d # Any digit. The same as [0-9] /D # Any non-digit. The same as [^0-9] /s # Any whitespace character: space,51); font-family:Arial; font-size:14px; line-height:26px"> # tab,newline,etc /S # Any non-whitespace character /b # A word boundary,outside [] only /B # No word boundary 象$,|,[,),/,/这样的字符是很特殊的,如果要引用它们,必须在前面加一个反斜线: /| # Vertical bar /[ # An open square bracket /) # A closing parenthesis /* # An asterisk /^ # A carat symbol // # A slash // # A backslash RE的例子 我们前面提到过,用RE最好慢慢来。下面是一些例子,当使用它们时应方在/.../中。 [01] # Either "0" or "1" //0 # A division by zero: "/0" // 0 # A division by zero with a space: "/ 0" ///s0 # A division by zero with a whitespace: # "/ 0" where the space may be a tab etc. // *0 # A division by zero with possibly some # spaces: "/0" or "/ 0" or "/ 0" etc. ///s*0 # A division by zero with possibly some # whitespace. ///s*0/.0*# As the previous one,but with decimal # point and maybe some 0s after it. Accepts # "/0." and "/0.0" and "/0.00" etc and # "/ 0." and "/ 0.0" and "/ 0.00" etc. 3、替换和翻译 Perl可以在匹配的基础上进行替换操作。可以用s函数实现这个功能。如果不使用匹配操作符,那么替换被认为对$_变量进行操作。 在字符串$sentence中用London替换london可以用下面的表达式: $sentence =~ s/london/London/ 用$_变量可以这样做: s/london/London/ 表达式的结果是替换发生的次数,所以或者是0或者是1。 选项 上面的例子只替代第一个匹配的字符串,用g参数可以进行全程替换: s/london/London/g 返回的结果为0或被替换的次数。 如果我们想替换lOndon,lonDON,LoNDoN等,可以这样做: s/[Ll][Oo][Nn][Dd][Oo][Nn]/London/g 但是可以有更简单的方式 - 使用i选项(忽略大小写): s/london/London/gi 记忆方式 如果记住匹配方式,以后用起来可以更方便。任何发生在括号内的匹配被记在变量$1,...,$9中。这些用在相同RE中的字符串可以用/1,/9表示: $_ = "Lord Whopper of Fibbing"; s/([A-Z])/:/1:/g; print "$_/n"; 这段代码替换任何大写字母为被冒号包围的形式。结果是:L:ord :W:hopper of :F:ibbing。变量$1,$9是只读变量,不可以修改它们。 另一个例子,判断语句: if (/(/b.+/b) /1/) print "Found $1 repeated/n"; 将判断任何重复的单词。每个/b代表一个单词边界,.+与任何非空字符串相匹配,因此/b.+/b匹配任何两个单词边界中的内容。然后被括号记住,存储在/1中,$1被程序的其余部分使用。 下面的表达式交换$_变量的第一个和最后一个字符: s/^(.)(.*)(.)$//3/2/1/ ^和$匹配行的开始和结尾。/1存储第一个字符,/2存储除第一个和最后一个字符之外的部分,最后一个字符存储在/3中。然后/1和/3进行互换。 匹配之后,可以使用特殊的只读变量$~、$&和$'找到查询之前、之中和之后的内容。所以在 /pp/; 之后,下面的表达式都为真(eq表示字符串匹配判断)。 $` eq "Lord Wo"; $& eq "pp"; $' eq "er of Fibbing"; 在替换表达式中可以使用变量,因此 $search = "the"; s/$search/xxx/g; 将把任何出现的the替换为xxx。如果想替换there,则不能使用s/$searchre/xxx/,因为程序会把它当作变量$searchre。可以用花括号实现there的替换: s/${search}re/xxx/; 翻译 tr函数实现字符对字符的翻译。下面的表达式替换变量$sentence中的每个a为e,b为d,c为f。表达式返回替换的次数。 $sentence =~ tr/abc/edf/ 大多数特殊RE代码不能用在tr函数中。例如,下面的语句计算$sentence变量中的星号数,然后存储在变量$count中。 $count = ($sentence =~ tr/*/*/); 但是"-"仍然表示"between"。下面的语句把变量$_转换为大写形式: tr/a-z/A-Z/; 1、Split? Perl中的一个非常有用的函数是split - 把字符串进行分割并把分割后的结果放入数组中。这个函数使用规则表达式(RE),如果未特定则工作在$_变量上。 split函数可以这样使用: $info = "Caine:Michael:Actor:14,Leafy Drive"; @personal = split(/:/,$info); 其结果是: @personal = ("Caine","Michael","Actor","14,Leafy Drive"); 如果我们已经把信息存放在$_变量中,那么可以这样: @personal = split(/:/); 如果各个域被任何数量的冒号分隔,可以用RE代码进行分割: $_ = "Capes:Geoff::Shot putter:::Big Avenue"; @personal = split(/:+/);? 其结果是 @personal = ("Capes","Geoff","Shot putter","Big Avenue"); 但是下面的代码: 的结果是 单词可以被分割成字符,句子可以被分割成单词,段落可以被分割成句子: @chars = split(//,$word); @words = split(/ /,$sentence); @sentences = split(//./,$paragraph); 在第一句中,空字符串在每个字符间匹配,所以@chars数组是一个字符的数组。 2、关联数组 顺序表数组允许我们按照数字对其元素进行访问。数组@food的第一个元素是$food[0],第二个元素是$food[1],等等。但是Perl也允许我们建立可以通过字符串进行访问的数组,称为关联数组(associative arrays)。 我们用括号定义关联数组,但是数组名前有一个%符号。假设我们建立一个关于人和他们的年龄的数组,则可以这样: %ages = ("Michael Caine",39,51); font-family:Arial; font-size:14px; line-height:26px">"Dirty Den",34,51); font-family:Arial; font-size:14px; line-height:26px">"Angie",27,51); font-family:Arial; font-size:14px; line-height:26px">"Willy","21 in dog years",51); font-family:Arial; font-size:14px; line-height:26px">"The Queen Mother",108); 现在我们可以这样找到人们的年龄: $ages{"Michael Caine"};# Returns 39 $ages{"Dirty Den"};# Returns 34 $ages{"Angie"};# Returns 27 $ages{"Willy"};# Returns "21 in dog years" $ages{"The Queen Mother"};# Returns 108 访问单个元素时用$,而不是% - 因为单个元素是标量。关联数组的索引包含在花括号内。 可以通过把关联数组赋给一个表数组变量把关联数组转换为表数组。表数组也可以转换为关联数组 - 通过把它赋值给关联数组变量。理想地,表数组将有偶数个元素: @info = %ages;# @info is a list array. It # now has 10 elements $info[5];# Returns the value 27 from # the list array @info %moreages = @info;# %moreages is an associative # array. It is the same as %ages 操作符 关联数组的元素没有顺序(有点象hash表),但是可以通过keys函数和values函数轮流访问所有的元素: foreach $person (keys %ages) print "I know the age of $person/n"; foreach $age (values %ages) print "Somebody is $age/n"; 当keys被调用时,返回关联数组的keys的列表。当values被调用时,返回数组的值的列表。这两个函数返回的列表的顺序相同,但是这个顺序与元素被输入的顺序没有关系。 当keys和values在一个标量环境中被调用时,它们返回关联数组中的key/value对的数目。 有一个each函数返回一个关键字和其值的两个元素的列表。每调用each一次,它返回另一个key/value对: while (($person,$age) = each(%ages)) print "$person is $age/n"; 环境变量 当在UNIX中运行perl程序或任何script时,会遇到某些环境变量。比如,USER包含你的用户名,DISPLAY确定图形使用的屏幕。当在WWW中运行perl CGI script时,也有环境变量存储其它有用的信息。所有这些变量和它们的值存储在关联数组%ENV中,其关键字为变量名。可以试试这个perl程序: print "You are called $ENV{'USER'} and you are "; print "using display $ENV{'DISPLAY'}/n"; 3、子过程 和很多语言一样,Perl允许用户定义自己的函数,称为子过程(subroutine)。它们可以放在程序的任何地方,但是最好把它们全放在程序的顶部或尾部。 子过程的形式如下: sub mysubroutine print "Not a very interesting routine/n"; print "This does the same thing every time/n"; 可以给子过程传递任何数量的参数。下面的语句都可以调用这个子过程。注意子过程在调用时在名称前使用一个&字符: &mysubroutine;# Call the subroutine &mysubroutine($_);# Call it with a parameter &mysubroutine(1+2,$_);# Call it with two parameters 参数 在上面的例子中参数被接受但是被忽略。当子过程被调用时,任何参数都被传递到特殊表数组变量@_中,这个变量与$_没有任何关系。下面的子过程只是打印它被调用的参数的列表。后面是一些调用它的例子。 sub printargs print "@_/n"; &printargs("perly","king");# Example prints "perly king" &printargs("frog","and","toad"); # Prints "frog and toad" 和任何其它列表数组一样,@_中的单个元素可以通过方括号访问: sub printfirsttwo print "Your first argument was $_[0]/n"; print "and $_[1] was your second/n"; 要注意的是标量$_[0]和$_[1]等与标量$_没有任何关系。 返回值 子过程的结果总是最后被赋值。下面的子过程返回其两个输入参数中较大的,然后是一个调用这个子过程的例子。 sub maximum if ($_[0] > $_[1]) $_[0]; $_[1]; $biggest = &maximum(37,24);# Now $biggest is 37 上面的&printfirsttwo子过程也返回一个值,这时是1。这是因为这个子过程所做的最后一件事是print语句,打印成功的结果总是1。 局部变量 @_变量对当前子过程是局部的,当然$_[0]、$_[1]、$_[2]等也是这样。其它变量也可以被设置为局部的,这在我们开始改变输入参数时是有用的。下面的子过程判断一个字符串是否在另一个中,不包括空格。然后是一个引用它的例子。 sub inside local($a,$b);# Make local variables $a =~ s/ //g;# Strip spaces from $b =~ s/ //g;# local variables ($a =~ /$b/ || $b =~ /$a/);# Is $b inside $a # or $a inside $b? &inside("lemon","dole money");# true 实际上,可以简化为 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |