Perl正则表达式讲解
Perl正则表达式讲解9.3.1原则1
正则表达式有三种形式:匹配、替换和转换。
在表 9-1 中列有三种正则表达式运算符。
接下来对每一个表达式给出详尽解释。匹配:m/<regexp>/这种形式表明在//内部的正则表达将用于匹配 = ~或 !~左边的标量。为了语法上的简化用/<regexp>/,略去m。
替换:s/<regexp>/<substituteText>/这种形式表明正则表达式<regexp>将被文本<substituteText>替换,为了语法的简化用/<regexp>/<substituteText>略去s。
·转换:tr/<charClass>/<substituteClass>/这种形式包含一系列的字符—/<charClass>—同时把它们替换为<substituteClass>。注意转换<tr>并不真正是一个正则表达式,但是对于用正则表达式难于处理的数据常使用它来进行操纵。因此,tr/[0-9]/9876543210.组成1223456789,987654321等字符串。
通过使用=~(用英语讲:does,与“进行匹配”同)和!~(英语:doesnt,与“不匹配”同)把这些表达式易做图到标量上。作为这种类型的例子,下面我们给出六个示例正则表达式及相应的定义:
$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! ";}
打印所有包含模式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/x0127/; # match binary character x01, and
# octal character 27.
$variable =~ s/ //; # 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替换为:
$vari
补充:综合编程 , 安全编程 ,