首页 » 精通正则表达式(第3版) » 精通正则表达式(第3版)全文在线阅读

《精通正则表达式(第3版)》Substitution运算符

关灯直达底部

The Substitution Operator

Perl的substitution运算符s/…/…/不但能够匹配,还能够替换匹配的文字。通常的形式是:

$text=~s/regex/replacement/modifiers

简单来说,regex 匹配的文本会替换为 replacement 的值。如果使用了/g,这个正则表达式会重复应用到文本中进行匹配,每次匹配的内容都会被替换。

与 match 操作一样,如果目标字符串在变量$_中,目标运算元和=~都不是必须的。match运算符可以省略m,而substitution不能省略s。

我们已经看到,match运算符是非常复杂的——它的工作原理,它的返回值,都取决于它所在的应用场合,目标字符串的pos,以及使用的修饰符。相反,substitution运算符很简单:它返回的信息是不变的(表示替换的次数),影响它的修饰符也很好理解。

你可以使用第292页介绍的所有核心修饰符,但是substituion运算符还支持另外两个修饰符,/g,以及马上将要介绍的/e。

运算元replacement

The Replacement Operand

在普通s/…/…/中,replacement紧跟在regex之后;m/…/使用两个分隔符,而这里要使用3个。如果正则表达式使用对称的分隔符(例如<…>),则replacement有自己的一对分隔符(这样总共就有4个分隔符)。举例来说,s{…}{…}和s[…]/…/和s<…>/'…/'都是合法的。这种情况下,两对分隔符可以用空白字符分隔,如果使用了空白字符,还可以添加注释。对称的分隔符通常在/x或/e中使用。

请注意区分regex和replacement。regex会按照正则表达式的方式来解析,有自己的分隔符(☞291)。replacement 则会当作普通的双引号字符串来解析和求值(evaluate)。求值会在匹配之后进行(如果使用了/g,每次匹配之后都会求值),所以$1之类的变量能够指向对应的匹配内容。

在下面两种情况下,replacement不会按照双引号字符串来解析:

●replacement的分隔符是单引号,此时作为单引号字符串,不会进行变量插值。

●使用了/e修饰符(下一节讨论),replacement会作为一小段Perl代码而不是双引号字符串。这一小段Perl代码会在每次匹配之后执行,结果作为replacement。

/e修饰符

The/e Modifier

/e修饰符会把replacement作为一段Perl代码来进行求值,这就类似eval{…}。代码装载时,首先会检查这段代码的语法,确保没有错误,但是每次匹配之后都会对代码重新求值。每次匹配之后,replacement都会在scalar context中重新求值,结果作为replacement。下面有个简单的例子:

$text=~s/-time-/localtime/ge;

在scalar context中,它会用Perl的localtime函数的结果(也就是返回表示当前时间的文本,例如“Mon Sep 25 18:36:51 2006”)替换「-time-」。

因为求值是每次匹配之后进行的,我们可以通过$1等变量引用匹配的内容。例如,URL中不容许出现的特殊字符,可以编码为百分号“%”加两位十六进制数的形式。为了编码所有这种字符,可以这样:

$url=~s/([^a-zA-Z0-9])/sprintf(/'%%%02x/',ord($1))/ge;

下面的程序可以用来解码:

$url=~s/%([0-9a-f][0-9a-f])/pack("C",hex($1))/ige;

简单地说,sprintf(/'%%%02x/',ord(character))把字符转换为对应的 URL 编码,而pack("C",value)的作用相反,请参考你常用的Perl文档获取更多信息。

多次使用/e

通常情况下,对单个运算符多次使用同一修饰符没有特殊意义(只有让读者更困惑),但是重复/e修饰符却会改变replacement的替换过程。正常情况下,replacement会进行一次求值,但是如果‘e’的数目多于1个,则Perl又会对求值的结果进行求值,如此一直进行下去,求值的次数与‘e’的数目一样多。或许它的主要价值是用作比较Perl代码复杂性的测试。

不过此功能并非完全无用。如果需要手动进行变量插值(例如从配置文件读入字符串)。也就是说,有一个字符串‘…$var…’,我们希望把‘$var’替换为$var的值。

简单的办法是:

$data=~s/($[a-zA-Z_]w*)/$1/eeg;

如果不使用/e,则会替换匹配的‘$var’自身,这没什么用。使用一个/e,会对$1重新求值,得到‘$var’,这样也没什么意义,同样是用匹配的文本替换自身。但是如果使用两个/e,则‘$var’会重新求值,得到内容,这样就模拟了变量插值。

应用场合与返回值

Context and Return Value

根据 context和/g的不同组合,match运算符会返回不同的值。不过,substitution运算符没有这么复杂——它返回的要么是替换发生的次数,要么是空字符串,表示没有发生任何替换。

为使用方便,返回值为Boolean时(例如在if条件语句中),只要发生了替换,返回值就为true,false表示没发生替换。