Chinaunix首页 | 论坛 | 博客
  • 博客访问: 547518
  • 博文数量: 201
  • 博客积分: 7734
  • 博客等级: 少将
  • 技术积分: 1994
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-09 19:18
文章分类

全部博文(201)

文章存档

2011年(28)

2010年(173)

分类:

2010-08-21 23:52:53

9.3.1原则1

正则表达式有三种形式:匹配、替换和转换。

在表 9-1 中列有三种正则表达式运算符。

接下来对每一个表达式给出详尽解释。

匹配:m//这种形式表明在//内部的正则表达将用于匹配 = ~或 !~左边的标量。为了语法上的简化用//,略去m。

替换:s///这种形式表明正则表达式将被文本替换,为了语法的简化用//略去s。


·转换:tr///这种形式包含一系列的字符—/—同时把它们替换为

注意转换并不真正是一个正则表达式,但是对于用正则表达式难于处理的数据常使用它来进行操纵。因此,tr/[0-9]/9876543210.组成1223456789,987654321等字符串。

通过使用=~(用英语讲:does,与“进行匹配”同)和!~(英语:doesn't,与“不匹配”同)把这些表达式捆绑到标量上。作为这种类型的例子,下面我们给出六个示例正则表达式及相应的定义:

$scalarName =~ s/a/b; # substitute the character a for b, and return true if this can happern

$scalarName =~ m/a; # does the scalar $scalarName have an a in it?

$scalarName =~ tr/A-Z/a-z/; # translate all capital letter with lower case ones, and return ture if this happens

$scalarName !~ s/a/b/; # substitute the character a for b, and return false if this indeed happens.

$scalarName !~ m/a/; # does the scalar $scalarName match the character a? Return false if it does.

$scalarName !~ tr/0-9/a-j/; # translate the digits for the letters a thru j, and return false if this happens.

如果我们输入像 horned toad =~ m/toad/ 这样的代码,则出现图 9-1 所示情况:

另外,如果读者正在对特定变量 $_ 进行匹配(读者可能在while循环,map或grep中使用),则可以不用!~和=~。因而,以下所有代码都会合法:

my @elemente = (' al' ,' a2' ,' a3' ,' a4' ,' a5' );

foreach (@elements) {s/a/b/;}

程序使 @elements 等于b1,b2.b3,b4,b5。另外:

while(<$FD>) {print if (m/ERBOR/);}

打印所有包含 error 字符串的行:

if (grep(/pattern/, @lines)) {print " the variable \@lines has pattern in it!\n";}

打印所有包含模式pattern内容的行,这直接引入下一原则。

 

9.3.2 原则2

正则表达式仅在标量上匹配。

注意这里标量的重要性,如果读者试一试如下代码:

@arrayName = (' variablel', 'variable2');

@arrayName =~ m/variable/; # looks for ' variable' in the array? No! use grep instead

那么@arrayName匹配不成功! @arrayName被Perl解释为2,于是这意味着读者在输入:

' 2' =~ m/variable/;

至少讲这不能给出预想的结果。如果读者想这样做,输人为:

grep(m/variable/, @arrayName);

该函数通过@arrayName中的每一个元素进行循环,返回(在标量环境中)匹配的次数,同时在数组环境中返回匹配元素的实际列表。

 

9.3.3 原则3

对于给定的模式串,正则表达式只匹配最早出现的匹配项。匹配时缺省一次只匹配或替换一次。

这个原则使用称为“回溯”的过程指出如何匹配一个给定的字符串;如果发现了一个局部匹配进而找到使该匹配无效的东西,正则表达式在字符串中“回溯”最小的可能数量,这个数量的字符要保证不丢失任何匹配。

对于理解正则表达式正在做什么,这个原则是最有帮助的一个,同时不需要与Perl一样的形式来理解它正在做什么。假定有如下模式:

' Silly people do silly things if in silly moods'

同时想匹配如下模式:‘

' silly moods'

那么正则表达式引擎匹配silly,接着遇到people的P,至此,正则表达式引擎知道第一个silly不匹配,于是正则表达式引擎移到 P 且继续寻求匹配。它接着遇到第二个silly,于是来匹配moods。然而得到的是字母 t(在thing中),于是移到 things中的 t 处,继续进行匹配。当引擎遇到第三个silly并且尽力匹配moods时,匹配成功,匹配最后完成。所发生的情况如图 9-2 所示。

当我们遇到通配符时回溯将变得更加重要。如果在同一正则表达式中有几个通配符,且所有的通配符交织在一起,那么这里就有病态情形出现,在这种情形下,回溯变得非常昂贵。看如下表达式: :

$line = m/expression.*matching.*could.*be.*very.*expensive.*/

.* 代表一个通配符,它意味着“匹配任意字符(换行符除外)零次或多次”。这个过程有可能花很长时间;如果在未匹配过的字符串末尾有可能匹配,那么引擎将发狂地回溯。为得到这方面的更多信息,请留意关于通配符方面的原则。

如果读者发现类似于上面的情形,那么通配符需将正则表达式分解成小功部分。换句话讲,简化自己的正则表达式。

 

9.3.4 原则4

正则表达式能够处理双引号字符串所能处理的任意和全部的字符。

在s///运算符(s/*//),或者m//运算符m/*/的第一个分隔区,位于其中的条目确实能像双引号字符串一样对待(带有一些额外的附加功能,名义上的特殊正则表达式字符!后面描述)。读者可用他们进行内插:

$variable = ' TEST' ; $a =~ m/${variable}aha/;

和:

$a = " ${variable}aha" ;

二者都指向同一字符串:前者在$a中匹配字符串TESTaha.后者把$a设置为字符串 TESTaha。因为正则表达式处理双引号字符串能处理的每个字符,所以可以执行下列操作:

$expression = ' hello';

@arrayName = (' elem1', ' elem2');

$variable =~ m/$expression/; # this equals m/hello/;

在这里,我们简单地把$expression扩展为hello而得到m/hello/。这个技巧也可用于数组:

$variable =~ m/@arrayName/; # this equals m/elem1 elem2/;

在这里,表达式等价于 m/elem1 elem2/。如果特殊变量$"被设置为 |.则表达式将等价于 m/elem | elem2/,正如我们看到的,它匹配字符串的elem或者elem2。这种方法也可应用于特殊字符:

$variable =~ m/\x01\27/; # match binary character x01, and

# octal character 27.

$variable =~ s/\t\t\t//; # substitute three tabs for three spaces.

实际上,这里所讨论的除极少数例外以外,Perl处理在m//中的过程的确像处理在双引号中的一样。但是有例外:有某些对正则表达式引擎有明确意义的字符。那么,如果想匹配类似于正斜杠(/)或者园括引(())这样的字符会发生什么呢?这些字符对正则表达式引取有特殊意义:因而不能使用如下语句:

$variable=~ m//usr/local/bin/; # matches /usr/local/bin? NO! SYNTAX ERROR

因为Perl将把/解释为正则表达式的结束标记。这里有三种方法去匹配类似于上述特殊字符的方法。第一种方法是利用反料杠来“转义”想匹配的任意特殊字符一包括反斜杠。因而刚才给出的例子可变为:

$path =~ m/\/usr\/local\/bin/;

该程序尽力匹配 $path中的/usr/local/bin。第二种方法是使用一个不同的正则表达式字符。如果有许多字符要匹配,那么使用反斜杠则会变得很难看(路径字符尤其不好)。

幸运的是,Perl以一种合成形式来确决这个问题。因为在当读者输入m//或s///时需要给每个/加反斜杠,所以正则表达式允许读者将正则表达式的定界符(/)改为自己喜欢的任意字符。例如,我们可以使用双引号(")来避免大量的反斜杠:

$variable =~ m"/usr/local/bin"; # Note the quotation marks.

$variable =~ m"\"help\""; # If you are going to match quotation

# marks, you need to backslash them here. (as per\")

$variable =~ S" $variable" $variable"; # works in s///too.

出于好的初衷,我们在本书的前几章使用了这一约定。如果使用"作为读者的正则表达式字符,那么在用起来时它充当了好的记忆法,记住在这里所处理的实际上是字符串的变相反插入;否则,引号就远不如斜杠常用。

Perl允许使用{}()[]来书写正则表达式:

$variable =~ m{this works well with vi or emacs because the parens bounce};

$variable =~ m(this also works well);

$variable =~ s(substitute pattern) {for this pattern}sg;

这一原则对我们处理多行正则表达式非常方便。因为在这里可以不用圆括号,所以读者可以开始把表达式作为“微型函数”对待(如果读者有像emacs或vi这样的合理的智能编辑器),换句话讲,读者可在表达式的开始和结尾部分之间往返。

第三种方法是利用函数quotemeta()来自动地加反斜杠。如果输入如下代码:

$variable =~ m" $scalar";

则$scalar将为被插且被转变为标量的值。这里有一个警告:任何一个特殊字符都将被正则表达式引擎影响,并且可能引起语法错误。因此,如果标量为:

$scalar = " ({";

那么输入如下代码:

$variabie =~ m" $scalar" ;

就等价于是说:$variable =~ m"({",而这是一个运行时语法错误。如果表达式为如下形式:

$scalar = quotemeta(' ({');

则表达式会使$scalar变为\(\{,且把$scalar替换为:

$variable =~ m" \(\{" ;

这样才可以匹配到读者愿意匹配的字符串({。

阅读(808) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~