Perl 语言概览,高屋建瓴、欲招人之耳目(四)

1.6 流程控制

1.6.1 什么是真

  ·除了””和”0”,所有字符串为真
  ·除了 0,所有数字为真
  ·所有引用为真
  ·所有未定义的值为假.

1.6.2 If 和 unless 语句

   if (case1) {...} elsif (case2) {...} elsif (case3) {...}  else {...}

为节约版面,全写在一行了。if/elsif/else 后的大括号是必须的,这和 C/Java中不一样,elsif 同 pl/sql 的写法。

象在英语中说“如果这不是真的,就做某事”,你可以使用 unless 语句:

unless ($destination eq $home) { print "I'm not going home.\en"; }

1.6.3 循环

Perl 有四种循环语句的类型:while,until,for 和 foreach。

1.6.3.1 while 和 until 语句

while ($line = <GRADES>) {...}

这句代码将文件的下一行内容赋值给变量 $line 并且返回 $line 的值.当最后达到文件结束的时候,读行操作符将返回未定义值,即为假,结束循环。
下面的代码处理命令行参数:

   while (@ARGV) {
      process(shift @ARGV);
   }

每次循环,shift 操作符都从参数数组中删除一个元素(同时返回这个元素),当数组 @ARGV 用完时循环自动退出,这时候数组长度变为 0,而在 Perl 中认为 0 为假。所以数组本身已经变为“假”--以数组的长度作为 while 的条件。

Perl 的 for 语句和 Java 的一样。下面是 foreach 的用法,遍历的各种列表。

foreach $user (@users) { ... }
foreach $key (sort keys %hash) { ... }

1.6.3.4 跳出控制结构: next 和 last

next 和 last 相当于 java 的 continue 和 break;而且也是可以用标签的,下面是结合标签的用法。

LINE: while ($line = <ARTICLE>) {
    last LINE if $line eq "\en"; # 在第一个空白行处停止
    next LINE if $line =~ /^#/; # 忽略注释行
    # 你的东西放在这里
}

1.7 正则表达式

正则表达式是 Perl 文本处理的核心。没有一种语言能象 Perl 一样将正则表达式和语言结合成一体。

未明确绑定字符串时,Perl 会对缺省字符串(特列变量$_)进行操作。

正则表达式有几种使用方法:

1. 确定一个字符串中是否存在某个模式
   if (/Windows 95/) { print "Time to upgrade?\n" }
2. 替换操作符
   s/Windows/Linux/;
3. 模式不仅可以声明某地方是什么,同样也可以声明某地方不是什么。因此 split 操作符使用了一个正则表达式来声明哪些地方不能匹配。在 split 中,正则表达式定义了各个数据域之间定界的分隔符。
   ($good, $bad, $ugly) = split(/,/, "vi,emacs,teco");

open(FILE,"c:\\t.pl");
while ($line = <FILE>) {
    print $line if ($line =~ /chop/);
}
打印含 chop 的行,这里 =~ 符号(模式绑定操作符)告诉 Perl 在 $line 中寻找匹配正则表达式“chop”。

1.7.1 量词

\d{7,11}、\d{7,}、\d{7}、 /bam{2}/、/(bam){2}/ 的意义
在缺省状态下,Perl 量词都是贪婪的,也就是他们将尽可能多地匹配一个字符串中最大数量的字符

如果你使用 /\d+/ 来匹配字符串“1234567890”,那么正则表达式将匹配整个字符串。当你使用“.”时特别需要注意,例如有下边一个字符串:

   larry:JYHtPh0./NJTU:100:10:Larry Wall:/home/larry:/bin/tcsh

并且想用 /.+:/ 来匹配“larry:”,但是因为 + 是贪婪的,这个模式将匹配一直到 /home/larry: 为止。因为它尽可能多地匹配直到最后出现的一个冒号。有时候你可以使用反向的字符类来避免上边的情况,比如使用 /[^:]+:/,表示匹配一个或多个不是冒号的的字符(也是尽可能多),这样正则表达式匹配至第一个冒号。

另外,正则表达式将尽早进行匹配。甚至在它变得贪婪以前。(正则表达式也许贪婪,但不会错过满足条件的机会)。例如,并且你希望删除中间的所有的 x。如果你说:

   $_ = "fred xxxxxxx barney";
   s/x*//;  # $_ 仍然是 "fred xxxxxxx barney"

但是上面的代码并没有达到预想的目的,这是因为 x*(表示零次或多次“x”)在字符串的开始匹配了空字符串,因为空字符串具有零字符宽度,并且在 fred 的 f 字符前正好有一个空字串。
用 s/x+// 就能贪婪的替换掉 xxxxxxx。这与贪婪的特性不好区分。

1.7.2 最小匹配

在新版本 Perl 中,可以强制进行非贪婪匹配。在量词后面加上一个问号来表示最小匹配。我们同样的用户名匹配就可以写成 /.*?:/。这里的 .*? 现在尽可能少地匹配字符,而不是尽可能多的匹配字符。所以它将停止在第一个冒号而不是最后一个。就是用 ".*?" 替换原来的 ".+"。 

1.7.3 把钉子敲牢

特殊符号 \b 匹配单词边界,^ 和 $ 实际上是用于行的开头和结尾,而不是用于字串的。

1.7.4 反引用

正则表达式中的一对圆括弧使得这部分匹配到的东西将被记住以供以后使用,匹配到的组保存到一个个特殊变量中。

如何反向引用保存下来的匹配部分决定于你在什么地方使用它,如果在同一个正则表达式中,你可以使用反斜杠加上一个整数。从一开始计数。例如,为了匹配 HTML中 的标记如“Bold”,你可以使用 /<(.*?)>.*?<\/\1>/。这样强制模式的两个部分都匹配同样的字符串。在此,这个字符串为“B”.

如果不在同一个正则表达式,例如在替换的置换部分中使用反引用,你可以使用 $ 后边跟一个整数。看起来是一个以数字命名的普通标量变量。因此,如果你想将一个字符串的前两个词互相调换,你可以使用下面的代码:

   s/(\S+)\s+(\S+)/$2 $1/

上边代码的右边部分(第二第三个反斜杠之间)几乎就是一个双引号字符串,在这里可以代换变量。包括反向引用。这是一个强大的概念:代换是 Perl 成为一种优秀的文本处理语言的重要原因之一。另外一个原因就是模式匹配,当然,正则表达式方便将所需要的东西分离出来,而代换可以方便将这些东西放回字符串。

1.8 列表处理

   print reverse sort map {lc} keys %hash;

一行中堆叠几个列表操作符,数据流是从右到左,因为列表操作符从右开始操作参数。

并且希望分析一些包含象“12:59:59 am” 这样形式时间的字符串,你可以使用下面的写法:

   ($hour, $min, $sec, $ampm) = /(\ed+):(\ed+):(\ed+) *(\ew+)/;

这是一种同时设置多个变量的简便方法,但是你也可以简单的写:

   @hmsa = /(\ed+):(\ed+):(\ed+) *(\ew+)/;

本文链接 https://yanbin.blog/perl-overview-4/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

2 Comments
Inline Feedbacks
View all comments
Jack.Wang
15 years ago

大哥,研究的语言慢多的!

隔叶黄莺
15 years ago

工作所用吗

呵呵,低调……低调……