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 ,与“进行匹配”同)
和!~(英语:doesn't ,与“不匹配”同)把这些表达式捆绑
到标量上。作为这种类型的例子,下面我们给出六个示例
正则表达式及相应的定义:
$scalar $scalarName =~ s/a/b;Name =~ s/a/b;Name =~ s/a/b;  # substitute the character a for b, and return true if this can happern    # substitute the character a for b, and return true if this can happern  $scalarName =~ m/a;$scalarName =~ m/a;          # does the scalar $scalarName have an a in it?        # does the scalar $scalarName have an a in it?
~ tr/A $scalarName =~ tr/A--Z/a Z/a--# translate all capital letter with lower case ones, and retur z/;  # translate all capital letter with lower case ones, and return ture n ture if this happens if this happens
$scalarName !~ s/a/b/;$scalarName !~ s/a/b/;
# substitute the character a for b, and return false if this indeed happens.happens.
$scalarName !~ m/a/;$scalarName !~ m/a/;          # does the scalar $scalarName match the character a? Return false if it does.if it does.
$scalarName !~ tr/0$scalarName !~ tr/0--9/a 9/a--j/;j/;    # translate the digits for the letters a thru j, and return false if this happens.if this happens.
如果我们输入像 horned toad =~ m/toad/ 这样的代码,则出现图 9-1 所示情况:    另外,如果读者正在对特定变量 $_ 进行匹配(读者可能在while 循环,map 或grep 中使用),则可以不用!~和=~。因而,以下所有代码都会合法:
my @elemente = (' al' ,' a2' ,my @elemente = (' al' ,' a2' ,' a3' ,' a4' ,' a5' );' a3' ,' a4' ,' a5' );' a3' ,' a4' ,' a5' );
foreach (@elements) {s/a/b/;}foreach (@elements) {s/a/b/;}
程序使 @elements 等于b 1,b2.b3,b4,b5。另外:
while(<$FD>) {print if (m/ERBOR/);}      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 = (' variablel', 'variable2');
@arrayName = (' variablel', 'variable2');
@arrayName =~ m/variable/; # looks for ' variable' in the array? No! use grep instead    @arrayName =~ m/variable/; # looks for ' variable' in the array? No! use grep instead 那么@arrayName匹配不成功!
@arrayName被Perl解释为2,于是这意味着读者在输入:
' 2' =~ m/variable/;
' 2' =~ m/variable/;
至少讲这不能给出预想的结果。如果读者想这样做,输人为:
grep(m/variable/, @arrayName);
grep(m/variable/, @arrayName);
grep(m/variable/, @arrayName);
该函数通过@arrayName中的每一个元素进行循环,返回(在标量环境中)匹配的次数,同时在数组环境中返回匹配元素的实际列表。
9.3.3 原则3
对于给定的模式串,正则表达式只匹配最早出现的匹配项。匹配时缺省一次只匹配或替换一次。
这个原则使用称为“回溯”的过程指出如何匹配一个给定的字符串;如果发现了一个局部匹配进而到使该匹配无效的东西,正则表达式在字符串中“回溯”最小的可能数量,这个数量的字符要保证不丢失任何匹配。
对于理解正则表达式正在做什么,这个原则是最有帮助的一个,同时不需要与Perl一样的形式来理解它正在做什么。假定有如下模式:
' Silly people do silly things if in silly moods'
' Silly people do silly things if in silly moods'
' Silly people do silly things if in silly moods'
同时想匹配如下模式:‘
' silly moods'
' 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.*/
$line = m/expression.*matching.*could.*be.*very.*expensive.*/
$line = m/expression.*matching.*could.*be.*very.*expensive.*/
正则表达式任意内容.* 代表一个通配符,它意味着“匹配任意字符(换行符除外)零次或多次”。这个过程有可能花很长时间;如果在未匹配过的字符串末尾有可能匹配,那么引擎将发狂地回溯。为得到这方面的更多信息,请留意关于通配符方面的原则。
如果读者发现类似于上面的情形,那么通配符需将正则表达式分解成小功部分。换句话
讲,简化自己的正则表达式。
9.3.4 原则4
正则表达式能够处理双引号字符串所能处理的任意和全部的字符。
在s///运算符(s/*//),或者m//运算符m/*/的第一个分隔区,位于其中的条目确实能像双引号字符串一样对待(带有一些额外的附加功能,名义上的特殊正则表达式字符!后面描述)。读者可用他们进行内插:
$variable = ' TEST' ;$variable = ' TEST' ;$variable = ' TEST' ;
$a =~ m/${variable}aha/;    $a =~ m/${variable}aha/;
和:
$a = " ${variable}aha" ;    $a = " ${variable}aha" ;
二者都指向同一字符串:前者在$a 中匹配字符串TESTaha .后者把$a 设置为字符串  TESTaha 。因为正则表达式处理双引号字符串能处理的每个字符,所以可以执行下列操作:        $expression = ' hello';$expression = ' hello';$expression = ' hello';
', ' elem2');    @arrayName = (' elem 1', ' elem2');
$variable =~ m/$expression/; # this equals m/hello/;    $variable =~ m/$expression/; # this equals m/hello/;
在这里,我们简单地把$expression 扩展为hello 而得到m/hello/。这个技巧也可用于数组:
$variable =~ m    $variable =~ m/@arrayName/; # this equals m/elem  elem2/;/@arrayName/; # this equals m/elem 1 elem2/;
在这里,表达式等价于 m/elem 1 elem2/。如果特殊变量$"被设置为 |.则表达式将等价于 m /elem | elem2/,正如我们看到的,它匹配字符串的elem 或者elem2。这种方法也可应用于特殊字符:
$variable =~ m/$variable =~ m/\1x01\\27/;27/;  , and # match binary character x01, and
# octal character 27.# octal character 27.
$va    $variable =~ s/riable =~ s/\t \t \t//;t//;  # substitute three tabs for three spaces.# substitute three tabs for three spaces.
实际上,这里所讨论的除极少数例外以外,Perl处理在m//中的过程的确像处理在双引号中的一样。但是有例外:有某些对正则表达式引擎有明确意义的字符。那么,如果想匹配类似于正斜杠(/)或者园括引(())这样的字符会发生什么呢?这些字符对正则表达式引取有特殊意义:因而不能使用如下语句:
/usr/local/bin? NO! SYNTAX ERROR
~ m//usr/local/bin/;  # matches /usr/local/bin? NO! SYNTAX ERROR $variable=~ m//usr/local/bin/;  # matches
$variable
/usr/local/bin? NO! SYNTAX ERROR 因为Perl将把/解释为正则表达式的结束标记。这里有三种方法去匹配类似于上述特殊字符的方法。第一种方法是利用反料杠来“转义”想匹配的任意特殊字符一包括反斜杠。因而刚才给出的例子可变为:
/bin/;
$path =~ m/
$path =~ m/\/usr\/local\/bin/;
该程序尽力匹配 $path中的/usr/local/bin。第二种方法是使用一个不同的正则表达式字符。如果有许多字符要匹配,那么使用反斜杠则会变得很难看(路径字符尤其不好)。
幸运的是,Perl以一种合成形式来确决这个问题。因为在当读者输入m//或s///时需要给每个/加反斜杠,所以正则表达式允许读者将正则表达式的定界符(/)改为自己喜欢的任意字符。例如,我们可以使用双引号(")来避免大量的反斜杠:
$variable =~ m"/usr/local/bin";  # Note the quotation marks.
$variable =~ m"/usr/local/bin";  # Note the quotation marks.
$variable =~ m"/usr/local/bin";  # Note the quotation marks.
ion
"";        # If you are going to match quotation
$variable =~ m"\"help\"";        # If you are going to match quotat
ion
")                                      # marks, you need to backslash them here. (as per\")    $variable =~ S" $variable" $variable";  # works in s///too.
$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 works well with vi or emacs because the parens bounce};
$variable =~ m(this also works well);
$variable =~ m(this also works well);
$variable =~ s(substitute pattern) {for this pattern}sg;
$variable =~ s(substitute pattern) {for this pattern}sg;
这一原则对我们处理多行正则表达式非常方便。因为在这里可以不用圆括号,所以读者可以开始把表达
式作为“微型函数”对待(如果读者有像emacs或vi这样的合理的智能编辑器),换句话讲,读者可在表达式的开始和结尾部分之间往返。
第三种方法是利用函数quotemeta()来自动地加反斜杠。如果输入如下代码:
$variable =~ m" $scalar";
$variable =~ m" $scalar";
则$scalar将为被插且被转变为标量的值。这里有一个警告:任何一个特殊字符都将被正则表达式引擎影响,并且可能引起语法错误。因此,如果标量为:
$scalar = " ({";
$scalar = " ({";
$scalar = " ({";
那么输入如下代码:
$variabie =~ m" $scalar" ;
$variabie =~ m" $scalar" ;
就等价于是说:$variable =~ m"({",而这是一个运行时语法错误。如果表达式为如下形式:
$scalar = quotemeta(' ({');
$scalar = quotemeta(' ({');
$scalar = quotemeta(' ({');
则表达式会使$scalar变为\(\{,且把$scalar替换为:
{" ;
$variable =~ m" \(\{" ;
$variable =~ m"
这样才可以匹配到读者愿意匹配的字符串({。
9.3.5 原则5
正则表达式在求值的过程中产生两种情况:结果状态和反向引用。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。