Chinaunix首页 | 论坛 | 博客
  • 博客访问: 470517
  • 博文数量: 142
  • 博客积分: 4126
  • 博客等级: 上校
  • 技术积分: 1545
  • 用 户 组: 普通用户
  • 注册时间: 2008-02-22 10:03
文章分类

全部博文(142)

文章存档

2011年(8)

2010年(7)

2009年(64)

2008年(63)

我的朋友

分类:

2009-04-24 10:11:52

1.11.1. 提出问题
你读到了一个内嵌变量引用的字符串,比如:
You owe $debt to me.
你想要把字符串里面的$debt 替换成这个变量对应的值。
1.11.2. 解决方案
如果这些内嵌变量是全局变量,可以通过符号引用(symbolic references)来进行替换:
 
$text =~ s/\$(\w+)/${$1}/g;
 
但如果这些内嵌变量可能是词法作用域(my)变量,可以加上/ee这样用:
 
$text =~ s/(\$\w+)/$1/gee;
 
1.11.3. 讨论

上面说的第一种方法主要是找到一个像变量名的东西,然后使用符号引用(symbolic dereferencing)来把它的内容内插到字符串里面。如果$1包含了这个变量名,那么${$1}就是该变量所包含的任何内容。不过,如果你在程序里面使用了use strict 'refs'这个宏编译指令的话,第一个方法是不行的,因为这个宏编译指令禁止符号引用(symbolic dereferencing)。
这有一个例子:
 
 

our ($rows, $cols);
no strict 'refs'; # 为了下面的 ${$1}/g

my $text;
($rows, $cols) = (24, 80);
$text = q(I am $rows high and $cols long); # 单引号字符串

$text =~ s/\$(\w+)/${$1}/g;
print $text;
# $>I am 24 high and 80 long

 
你可能见过/e这个正则表达式修饰符,在正则替换的时候,使用这个修饰符,替换部分就可以是一段代码而不是一个字符串。它适用于这样的情况:当你不知道应该替换成具体什么值,但是你知道应该怎样把值计算出来的时候。比如,把字符串里面的每个数字变成2倍:
 
$text = "I am 17 years old";
$text =~ s/(\d+)/2 * $1/eg;
 
当Perl在编译你的程序的时候看到了/e,它会提前把这个替换块的代码跟你程序的其他代码一起编译,这个时候这块替换代码还不会执行到。当替换发生的时候,$1被替换成匹配的字符串,然后执行类似这样的代码:
2 * 17
如果我们试着这样写的话:
 
$text = 'I am $AGE years old';      # 单引号字符串
$text =~ s/(\$\w+)/$1/eg;           # 错
 
假设$text里内嵌了变量$AGE, Perl会很忠诚的把$1换成$AGE,然后执行下面的代码:

'$AGE'

这行代码只是原样返回字符串而已。而我们需要的返回变量里面的内容,为了实现这个,需要再另加一个/e:
 
$text =~ s/(\$\w+)/$1/eeg;          # 可以发现词法作用域变量
 
是的,你想加几个/e就加几个。只有第一个/e是要被编译和进行语法检查的。这个就跟eval {BLOCK}差不多,只是它不捕获异常。它跟do {BLOCK}更像吧。
其他接下来的/e修饰符跟第一个是非常不一样的。它们更像eval "STRING"这样的结构。除非执行到了不然是不会编译的。这样有一个小小的好处就是在这块代码里面不再需要使用no strict 'refs'这个宏编译指令了,更大的优点在于,它跟符号引用(symbolic dereferencing)不一样,这样的方法可以找到那些用my生成的词法作用域变量,而这是符号引用做不到的。
下面的例子使用了/x修饰符,使到正则模式匹配部分可以包含空格和注释,使用/e来对替换部分当成代码进行求值。/e 修饰符让我们在非严重错误发生的时候可以有更好的控制:
# 扩展 $text中的变量值, 如果变量没有定义的时候,则插入一个错误信息

$text =~ s{
     \$                         # 发现一个像变量的字符串
    (\w+)                       # 并把变量名存进 $1
}{
    no strict 'refs';           # 为了下面的 ${$1}
    if (defined ${$1}) {
        ${$1};                    # 只能扩展全局变量
    } else {
        "[NO VARIABLE: \$$1]";  # 错误信息
    }
}egx;
 
在很久很久以前,字符串里面的$$1是指${$}1,即变量$$后面再跟一个1。这是很久以前的用法,这样你可以很容易的扩展进程ID变量$$来生成临时文件名。现在$$1是指${$1},也就是$1变量的反引用。我们之前专门写成${$1}只是为了看起来更清楚。
 
1.11.4. 参见

请参考:
perlre(1) 和 perlop(1) 里的s///; 大骆驼书 第5章;
perlfunc(1) 和 大骆驼书 第29章的 eval函数;
20.9这一节关于替换的类似应用
 
1.11.5 试验程序
 
阅读(542) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~