我正在尝试在s///
中使用变量。此示例代码按预期工作:
my $regex1 = "e";
my $regex2 = "2";
my @array = ("one two three", "green blue red");
$_ =~ s/$regex1/$regex2/gee foreach (@array);
print $_ foreach (@array);
但是,如果我尝试执行更复杂的正则表达式,例如:
my $regex1 = "^(w)";
my $regex2 = "u$1";
然后替换根本不起作用。我感觉 Perl 实际上是在寻找"插入符号括号反斜杠"等等,而不是将其解释为正则表达式。
您需要防止元字符的插值:
my $regex1 = '^(w)';
my $regex2 = '"u$1"';
(根据@ThisSuitIsBlackNot的评论更新(
原因是 Perl 插入双引号字符串,因此您的变量$regex1
和$regex2
不包含您需要的内容:
my $regex1 = "^(w)";
my $regex2 = "u$1";
print "$regex1n"; # ^(w)
print "$regex2n"; # empty line
因此,替换运算符按s/^(w)//gee
工作,当然找不到任何东西。
你真的不想这样做,因为允许人们将Perl代码传递给你的程序,这些代码将交给eval
并不是一件好事。 除了非常复杂之外,如果没有仔细检查,它还会让您陷入恶意。如果有人输入了aaa/"unlink *"
则必要的/ee
将删除您当前的文件夹
让我们先澄清一些事情。在s/PATTERN/REPLACEMENT/
中,只有PATTERN
是正则表达式。 REPLACEMENT
是一个简单的字符串,计算结果就好像是用双引号计算的
因此,让我们像这样编写程序。我把你所有的字符串都放在单引号里,因为你不想使用转义序列或变量插值。我也把你的/eeg
修饰符改成/g
.看起来你正在喷/e
,希望它可以工作,这不是编写软件的方法。
use strict;
use warnings 'all';
my $regex = 'e';
my $replacement = '2';
my @array = ('one two three', 'green blue red');
s/$regex/$replacement/g for @array;
print "$_n" for @array;
输出
on2 two thr22
gr22n blu2 r2d
现在您想将其更改为
my $regex = "^(w)";
my $replacement = "u$1";
这就是为什么我扔掉了你的双引号。Perl 尝试编译"^(w)"
,并将w
视为它无法识别的转义序列,因此您可以得到
Unrecognized escape w passed through
它假设你的意思只是w
.除非你想像"^(\w)"
那样转义反斜杠,否则你需要单引号来表示字符串^(w)
类似的事情也适用于$replacement
。 = "\u$1";
你将看到的第一件事是 Perl 试图将 $1
的当前值插入到双引号字符串中。它目前未定义,因此您可以得到
Use of uninitialized value $1 in ucfirst
但即便如此,它还是有义务并使用空字符串进行$1
,然后将其大写为您离开......空字符串
所以现在你已经设置
$regex = '^(w)';
$replacement = '';
所以什么都行不通也就不足为奇
了让我们再做一次你的程序,但这次使用单引号,这样就不会搞砸任何东西
use strict;
use warnings 'all';
my $regex = '^(w)';
my $replacement = 'u$1';
my @array = ('one two three', 'green blue red');
s/$regex/$replacement/g for @array;
print "$_n" for @array;
现在$regex
真的是^(w)
,$replacement
真的是u$1
.可能出现什么问题?
它工作正常。我们得到
u$1ne two three
u$1reen blue red
这正是我们要求的
但是现在您的/e
修饰符很有用。单个/e
将REPLACEMENT
作为表达式进行评估。如果我们想在其中粘贴$1 . 'xxx'
或类似内容,这将很有用,但由于表达式是$replacement
,我们根本没有任何优势:表达式$replacement
与插值$replacement
相同
我们需要另一个/e
吗?这将在第一个/e
的结果上调用eval
,所以我们要求eval 'u$1'
,并且不会编译,因为u$1
不是一个可行的Perl程序,所以eval
返回undef
,我们得到
Use of uninitialized value in substitution iterator
解决方案是将$replacement
变成可编译的程序。用双引号括起来,就像"u$1"
一样,它会变成一个非常短的Perl程序,它返回当前值$1
,第一个字符大写
我们需要为该字符串设置$replacement
,包括双引号,并避免像以前一样处理转义字符和$1
。如果我写
my $replacement = '"u$1"';
然后我得到的字符串"u$1"
包括双引号
现在让我们试试
use strict;
use warnings 'all';
my $regex = '^(w)';
my $replacement = '"u$1"';
my @array = ('one two three', 'green blue red');
s/$regex/$replacement/eeg for @array;
print "$_n" for @array;
输出
One two three
Green blue red
正如我所说,你真的不想这样做!