1.12 扩展用户输入里面的变量
时间:2007-01-05 来源:xiaoshengcaicai
1.12 扩展用户输入里面的变量
1.12.1 问题
你读到了一个内嵌变量引用的字符串,比如:
You owe $debt to me.
你想要把字符串里面的$debt 替换成这个变量对应的值。
1.12.2 解决方案
如果这些内嵌变量是全局变量,可以通过符号引用(symbolic references)来进行替换:
$text =~ s/\$(\w+)/${$1}/g;
如果这些内嵌变量可能是my变量,可以加上/ee这样用:
$text =~ s/(\$\w+)/$1/gee;
1.12.3 讨论
上面说的第一种方法主要是找到一个变量名,然后使用符号反引用(symbolic dereferencing)来把它的内容内插到字符串里面。如果$1包含了这个变量名,那么${$1}就是该变量包含的内容。不过,如果你在程序里面使用了use strict 'refs'这个宏编译指令的话,第一个方法是不行的,因为这个宏编译指令禁止符号反引用(symbolic dereferencing)。
our ($rows, $cols);
no strict 'refs'; # for ${$1}/g below
my $text;
($rows, $cols) = (24, 80);
$text = q(I am $rows high and $cols long); # like single quotes!
$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'; # note single quotes
$text =~ s/(\$\w+)/$1/eg; # WRONG
假设$text里内嵌了变量$AGE, Perl会很忠诚的把$1换成$AGE,然后执行下面的代码:
'$AGE'
这行代码只是原样返回字符串而已。而我们需要的返回变量里面的内容,为了实现这个,需要再加一个/e:
$text =~ s/(\$\w+)/$1/eeg; # finds my( ) variables
是的,你想加几个/e就加几个。只有第一个/e是要被编译和进行语法检查的。这个就跟eval {BLOCK}差不多,只是它不捕获异常。它跟do {BLOCK}更像吧。
其他接下来的/e修饰符跟第一个是非常不一样的。它们更像eval "STRING"这样的结构。除非执行到了不然是不会编译的。这样有一个小小的好处就是在这块代码里面不再需要使用no strict 'refs'这个宏编译指令了,更大的优点在于,它跟符号反引用(symbolic dereferencing)不一样,这样的方法可以找到那些用my生成的变量,而这是符号反引用做不到的。
下面的例子使用了/x修饰符,使到正则模式匹配部分可以包含空格和评论,使用/e来对替换部分当成代码进行求值。/e 修饰符让我们在非严重型错误发生的时候可以有更好的控制:
# expand variables in $text, but put an error message in
# if the variable isn't defined
$text =~ s{
\$ # find a literal dollar sign
(\w+) # find a "word" and store it in $1
}{
no strict 'refs'; # for $$1 below
if (defined ${$1}) {
${$1}; # expand global variables only
} else {
"[NO VARIABLE: \$$1]"; # error msg
}
}egx;
在很久很久以前,字符串里面的$$1是指${$}1,即变量$$后面再跟一个1。这是很久以前的用法,这样你可以很容易的扩展进程ID变量$$来生成临时文件名。现在$$1是指${$1},也就是$1变量的反引用。我们之前专门写成${$1}只是为了看起来更清楚。
1.12.4 参阅
perlre(1) 和 perlop(1) 里的s///;
Programming Perl 第5章;
perlfunc(1) 和 Programming Perl 第29章的 eval函数;
20.9这一节关于替换的类似应用