预定义替代的复杂替代品

时间:2016-07-28 21:25:10

标签: regex perl variables substitution evaluation

我正在尝试使用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实际上是在寻找“插入符号反斜杠”等等,而不是把它解释为正则表达式。

2 个答案:

答案 0 :(得分:1)

您需要阻止元字符的插值:

my $regex1 = '^(\w)';
my $regex2 = '"\u$1"';

(根据@ ThisSuitIsBlackNot的评论更新)

原因是Perl会插入双引号字符串,因此您的变量$regex1$regex2不包含您需要的内容:

my $regex1 = "^(\w)";
my $regex2 = "\u$1";
print "$regex1\n"; # ^(w)
print "$regex2\n"; # empty line

因此,替换运算符作为s/^(w)//gee工作,当然,找不到任何东西。

答案 1 :(得分:0)

真的不希望这样做,因为允许人们将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修饰符很有用。 /eREPLACEMENT评估为表达式。如果我们想在那里粘贴$1 . 'xxx'或类似内容,那将非常有用,但由于表达式为$replacement,我们根本没有任何优势:表达式$replacement与插值{{}相同1}}

我们需要另一个$replacement吗?这会在第一个/e的结果上调用eval,因此我们要求/e,因为eval '\u$1'不是可行的Perl,所以不会编译程序,\u$1返回eval,我们得到

undef

解决方案是将Use of uninitialized value in substitution iterator 转换为可编译程序。在它周围加上双引号,如$replacement将它变成一个非常短的Perl程序,它返回当前值"\u$1",第一个字符是大写的

我们需要将$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;

正如我所说, 真的 不想这样做!