📄 perlreg_8rule.html
字号:
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=gb_2312-80">
<META NAME="Generator" CONTENT="Microsoft Word 97">
<TITLE>Perl 正则表达式 8 大原则</TITLE>
</HEAD>
<BODY>
<FONT FACE="隶书" LANG="ZH-CN" SIZE=6><P ALIGN="CENTER">Perl正则表达式讲解</P>
</FONT>
<P ALIGN="right"><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>	</font><FONT FACE="宋体" LANG="ZH-CN" SIZE=1>摘自</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>《Perl编程详解》</font></P>
<FONT FACE="宋体" LANG="ZH-CN" SIZE=3>
<P ALIGN="right">感谢网友:<font color="#FF0000">rover</font>, <font color="#FF0000">wangmm</font>,
<font color="#FF0000">simbar</font>, <font color="#FF0000">menshen</font> 的辛勤劳动。</P>
<P ALIGN="right"> </P>
<P ALIGN="JUSTIFY"> 目录:<br>
<a href="#1">原则 1</a><br>
<a href="#2">原则 2</a><br>
<a href="#3">原则 3</a><br>
<a href="#4">原则 4</a><br>
<a href="#5">原则 5</a><br>
<a href="#6">原则 6</a><br>
<a href="#7">原则 7</a><br>
<a href="#8">原则 8</a><br>
<a href="#9">原则概括</a><br>
<a href="#10">正则表达式修饰符</a><br>
<a href="#11">匹配和 g 运算符</a><br>
<a href="#12">修饰符和环境</a><br>
</FONT>
<hr>
<FONT FACE="宋体" LANG="ZH-CN" SIZE=3>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"><B><a name="1"></a>9.3.1原则</b>1</P>
<P ALIGN="JUSTIFY"> 正则表达式有三种形式:匹配、替换和转换。</P>
<P ALIGN="JUSTIFY"> 在表 9-1 中列有三种正则表达式运算符。</P>
<P ALIGN="CENTER"><IMG SRC="images/Image1.jpg" WIDTH=552 HEIGHT=106></P>
<P ALIGN="JUSTIFY"> 接下来对每一个表达式给出详尽解释。</P>
<P ALIGN="JUSTIFY"> 匹配:m/<regexp>/这种形式表明在//内部的正则表达将用于匹配 = ~或 !~左边的标量。为了语法上的简化用/<regexp>/,略去m。</P>
<P ALIGN="JUSTIFY"> 替换:s/<regexp>/<substituteText>/这种形式表明正则表达式<regexp>将被文本<substituteText>替换,为了语法的简化用/<regexp>/<substituteText>略去s。</P>
<P ALIGN="left"><IMG SRC="images/Image2.jpg" WIDTH=215 HEIGHT=216 align="right"><br>
·转换:tr/<charClass>/<substituteClass>/这种形式包含一系列的字符—/<charClass>—同时把它们替换为<substituteClass>。</P>
<P ALIGN="JUSTIFY"> 注意转换<tr>并不真正是一个正则表达式,但是对于用正则表达式难于处理的数据常使用它来进行操纵。因此,tr/[0-9]/9876543210.组成1223456789,987654321等字符串。</P>
<P ALIGN="JUSTIFY"> 通过使用=~(用英语讲:does,与“进行匹配”同)和!~(英语:doesn't,与“不匹配”同)把这些表达式捆绑到标量上。作为这种类型的例子,下面我们给出六个示例正则表达式及相应的定义:</P>
</FONT><B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1>
<P ALIGN="JUSTIFY">$scalarName =~ s/a/b;	 # substitute the character a for b, and return true if this can happern</P>
<P ALIGN="JUSTIFY">$scalarName =~ m/a;	 # does the scalar $scalarName have an a in it?</P>
<P ALIGN="JUSTIFY">$scalarName =~ tr/A-Z/a-z/; # translate all capital letter with lower case ones, and return ture if this happens</P>
<P ALIGN="JUSTIFY">$scalarName !~ s/a/b/;	 # substitute the character a for b, and return false if this indeed happens.</P>
<P ALIGN="JUSTIFY">$scalarName !~ m/a/;	 # does the scalar $scalarName match the character a? Return false if it does.</P>
<P ALIGN="JUSTIFY">$scalarName !~ tr/0-9/a-j/;	 # translate the digits for the letters a thru j, and return false if this happens.</P>
</font></B><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"> 如果我们输入像 horned toad =~ m/toad/ 这样的代码,则出现图 9-1 所示情况:</P>
<P ALIGN="JUSTIFY"> 另外,如果读者正在对特定变量 $_ 进行匹配(读者可能在while循环,map或grep中使用),则可以不用!~和=~。因而,以下所有代码都会合法:</P>
</FONT><B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P ALIGN="JUSTIFY">my @elemente = (' al' ,' a2' ,' a3' ,' a4' ,' a5' );</P>
<P ALIGN="JUSTIFY">foreach (@elements) {s/a/b/;}</P>
</font></B><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">程序使 @elements 等于b1,b2.b3,b4,b5。另外:</P>
</FONT><B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P ALIGN="JUSTIFY"> while(<$FD>) {print if (m/ERBOR/);}</P>
</font></B><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>
<P ALIGN="JUSTIFY">打印所有包含 error 字符串的行:</P>
</FONT><B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P ALIGN="JUSTIFY"> if (grep(/pattern/, @lines)) {print " the variable \@lines has pattern in it!\n";}</P>
</font></B><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>
<P ALIGN="JUSTIFY">打印所有包含模式pattern内容的行,这直接引入下一原则。</P>
<B>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"><a name="2"></a>9.3.2 原则2</P>
</B>
<P ALIGN="JUSTIFY"> 正则表达式仅在标量上匹配。</P>
<P ALIGN="JUSTIFY"> 注意这里标量的重要性,如果读者试一试如下代码:</P>
</FONT><B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1>
<P ALIGN="JUSTIFY"> @arrayName = (' variablel', 'variable2');</P>
<P ALIGN="JUSTIFY"> @arrayName =~ m/variable/; # looks for ' variable' in the array? No! use grep instead</P>
</font></B><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"> 那么@arrayName匹配不成功! @arrayName被Perl解释为2,于是这意味着读者在输入:</P>
</FONT><B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P ALIGN="JUSTIFY"> ' 2' =~ m/variable/;</P>
</font></B><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"> 至少讲这不能给出预想的结果。如果读者想这样做,输人为:</P>
</FONT><B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P ALIGN="JUSTIFY"> grep(m/variable/, @arrayName);</P>
</font></B><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>
<P ALIGN="JUSTIFY">该函数通过@arrayName中的每一个元素进行循环,返回(在标量环境中)匹配的次数,同时在数组环境中返回匹配元素的实际列表。</P>
<B>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"><a name="3"></a>9.3.3 原则3</P>
</B>
<P ALIGN="JUSTIFY">对于给定的模式串,正则表达式只匹配最早出现的匹配项。匹配时缺省一次只匹配或替换一次。</P>
<P ALIGN="JUSTIFY">这个原则使用称为“回溯”的过程指出如何匹配一个给定的字符串;如果发现了一个局部匹配进而找到使该匹配无效的东西,正则表达式在字符串中“回溯”最小的可能数量,这个数量的字符要保证不丢失任何匹配。</P>
<P ALIGN="JUSTIFY"> 对于理解正则表达式正在做什么,这个原则是最有帮助的一个,同时不需要与Perl一样的形式来理解它正在做什么。假定有如下模式:</P>
</FONT><B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1>
<P ALIGN="JUSTIFY"> ' Silly people do silly things if in silly moods'</P>
</font></B><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"> 同时想匹配如下模式:‘</P>
</FONT><B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P ALIGN="JUSTIFY"> ' silly moods'</P>
</font></B><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"> 那么正则表达式引擎匹配silly,接着遇到people的P,至此,正则表达式引擎知道第一个silly不匹配,于是正则表达式引擎移到 P 且继续寻求匹配。它接着遇到第二个silly,于是来匹配moods。然而得到的是字母 t(在thing中),于是移到 things中的 t 处,继续进行匹配。当引擎遇到第三个silly并且尽力匹配moods时,匹配成功,匹配最后完成。所发生的情况如图 9-2 所示。</P>
<P ALIGN="JUSTIFY"> 当我们遇到通配符时回溯将变得更加重要。如果在同一正则表达式中有几个通配符,且所有的通配符交织在一起,那么这里就有病态情形出现,在这种情形下,回溯变得非常昂贵。看如下表达式: :</P>
</FONT><B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P ALIGN="JUSTIFY"> $line = m/expression.*matching.*could.*be.*very.*expensive.*/</P>
</font></B><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>
<P ALIGN="JUSTIFY"> .* 代表一个通配符,它意味着“匹配任意字符(换行符除外)零次或多次”。这个过程有可能花很长时间;如果在未匹配过的字符串末尾有可能匹配,那么引擎将发狂地回溯。为得到这方面的更多信息,请留意关于通配符方面的原则。</P>
<P ALIGN="JUSTIFY"> 如果读者发现类似于上面的情形,那么通配符需将正则表达式分解成小功部分。换句话讲,简化自己的正则表达式。</P>
<P ALIGN="CENTER"><IMG SRC="images/Image3.jpg" WIDTH=510 HEIGHT=404></P>
<B>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"><a name="4"></a>9.3.4 原则4</P>
</B>
<P ALIGN="JUSTIFY"> 正则表达式能够处理双引号字符串所能处理的任意和全部的字符。</P>
<P ALIGN="JUSTIFY"> 在s///运算符(s/*//),或者m//运算符m/*/的第一个分隔区,位于其中的条目确实能像双引号字符串一样对待(带有一些额外的附加功能,名义上的特殊正则表达式字符!后面描述)。读者可用他们进行内插:</P>
</FONT><B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1>
<P ALIGN="JUSTIFY"> $variable = ' TEST' ; $a =~ m/${variable}aha/;</P>
</font></B><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"> 和:</P>
</FONT><B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P ALIGN="JUSTIFY"> $a = " ${variable}aha" ;</P>
</font></B><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"> 二者都指向同一字符串:前者在$a中匹配字符串TESTaha.后者把$a设置为字符串 TESTaha。因为正则表达式处理双引号字符串能处理的每个字符,所以可以执行下列操作:</P>
</FONT><B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P ALIGN="JUSTIFY"> $expression = ' hello';</P>
<P ALIGN="JUSTIFY"> @arrayName = (' elem1', ' elem2');</P>
<P ALIGN="JUSTIFY"> $variable =~ m/$expression/; # this equals m/hello/;</P>
</font></B><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"> 在这里,我们简单地把$expression扩展为hello而得到m/hello/。这个技巧也可用于数组:</P>
</FONT><B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P ALIGN="JUSTIFY"> $variable =~ m/@arrayName/; # this equals m/elem1 elem2/;</P>
</font></B><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"> 在这里,表达式等价于 m/elem1 elem2/。如果特殊变量$"被设置为 |.则表达式将等价于 m/elem | elem2/,正如我们看到的,它匹配字符串的elem或者elem2。这种方法也可应用于特殊字符:</P>
</FONT><B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P ALIGN="JUSTIFY"> $variable =~ m/\x01\27/;	# match binary character x01, and</P>
<P ALIGN="JUSTIFY"> 				# octal character 27.</P>
<P ALIGN="JUSTIFY"> $variable =~ s/\t\t\t//;	# substitute three tabs for three spaces.</P>
</font></B><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>
<P ALIGN="JUSTIFY">实际上,这里所讨论的除极少数例外以外,Perl处理在m//中的过程的确像处理在双引号中的一样。但是有例外:有某些对正则表达式引擎有明确意义的字符。那么,如果想匹配类似于正斜杠(/)或者园括引(())这样的字符会发生什么呢?这些字符对正则表达式引取有特殊意义:因而不能使用如下语句:</P>
</FONT><B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P ALIGN="JUSTIFY"> $variable=~ m//usr/local/bin/; # matches /usr/local/bin? NO! SYNTAX ERROR</P>
</font></B><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"> 因为Perl将把/解释为正则表达式的结束标记。这里有三种方法去匹配类似于上述特殊字符的方法。第一种方法是利用反料杠来“转义”想匹配的任意特殊字符一包括反斜杠。因而刚才给出的例子可变为:</P>
</FONT><B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P ALIGN="JUSTIFY"> $path =~ m/\/usr\/local\/bin/;</P>
</font></B><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"> 该程序尽力匹配 $path中的/usr/local/bin。第二种方法是使用一个不同的正则表达式字符。如果有许多字符要匹配,那么使用反斜杠则会变得很难看(路径字符尤其不好)。</P>
<P ALIGN="JUSTIFY"> 幸运的是,Perl以一种合成形式来确决这个问题。因为在当读者输入m//或s///时需要给每个/加反斜杠,所以正则表达式允许读者将正则表达式的定界符(/)改为自己喜欢的任意字符。例如,我们可以使用双引号(")来避免大量的反斜杠:</P>
</FONT><B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P ALIGN="JUSTIFY"> $variable =~ m"/usr/local/bin"; # Note the quotation marks.</P>
<P ALIGN="JUSTIFY"> $variable =~ m"\"help\""; # If you are going to match quotation</P>
<P ALIGN="JUSTIFY"> # marks, you need to backslash them here. (as per\")</P>
<P ALIGN="JUSTIFY"> $variable =~ S" $variable" $variable"; # works in s///too.</P>
</font></B><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"> 出于好的初衷,我们在本书的前几章使用了这一约定。如果使用"作为读者的正则表达式字符,那么在用起来时它充当了好的记忆法,记住在这里所处理的实际上是字符串的变相反插入;否则,引号就远不如斜杠常用。</P>
</FONT>
<P ALIGN="JUSTIFY"><FONT FACE="宋体" LANG="ZH-CN" SIZE=3> Perl允许使用{}()[]来书写正则表达式:</font></P>
<P ALIGN="JUSTIFY"><B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1>$variable =~ m{this
works well with vi or emacs because the parens bounce};</font></b></P>
<B><FONT FACE="宋体" LANG="ZH-CN" SIZE=1>
<P ALIGN="JUSTIFY"> $variable =~ m(this also works well);</P>
<P ALIGN="JUSTIFY"> $variable =~ s(substitute pattern) {for this pattern}sg;</P>
</font></B><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"> 这一原则对我们处理多行正则表达式非常方便。因为在这里可以不用圆括号,所以读者可以开始把表达式作为“微型函数”对待(如果读者有像emacs或vi这样的合理的智能编辑器),换句话讲,读者可在表达式的开始和结尾部分之间往返。</P>
<P ALIGN="JUSTIFY"> 第三种方法是利用函数quotemeta()来自动地加反斜杠。如果输入如下代码:</P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -