为替换预定义一个复杂的替换

Predefining a complex replacement for substitution

我正在尝试使用 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";

那么替换根本不起作用。我感觉 Perl 确实在寻找 "caret parenthesis backslash" 等等,而不是将其解释为正则表达式。

您需要防止插入元字符:

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

(根据@ThisSuitIsBlackNot 的评论更新)

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

my $regex1 = "^(\w)";
my $regex2 = "\u";
print "$regex1\n"; # ^(w)
print "$regex2\n"; # 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";

这就是我去掉你的双引号的原因。 Perl 尝试编译 "^(\w)" 并将 \w 视为它无法识别的转义序列,因此您得到

Unrecognized escape \w passed through

并假设您的意思只是 w。除非你想像 "^(\w)" 那样转义反斜杠,否则你需要单引号来表示字符串 ^(\w)

类似的情况也适用于 $replacement。 = "\u$1";

您首先会看到 Perl 试图将 </code> 的当前值插入到双引号字符串中。它目前未定义,所以你得到</p> <blockquote> <pre><code>Use of uninitialized value in ucfirst

但即便如此,它还是强制使用空字符串作为 </code>,然后将其大写以供您离开……空字符串</p> <p>现在你已经设置好了</p> <pre><code>$regex = '^(w)'; $replacement = '';

所以毫无效果也就不足为奇了

让我们再做一次你的程序,但这次使用单引号,这样就不会搞砸了

use strict;
use warnings 'all';

my $regex       = '^(\w)';
my $replacement = '\u';

my @array = ('one two three', 'green blue red');

s/$regex/$replacement/g for @array;

print "$_\n" for @array;

现在 $regex 真的是 ^(\w)$replacement 真的是 \u。会出什么问题?

它工作正常。我们得到

\une two three
\ureen blue red

这正是我们要求的

但现在您的 /e 修饰符派上用场了。 single /eREPLACEMENT 计算为 expression。如果我们想在其中插入 . 'xxx' 或类似的东西,那将很有用,但是由于表达式是 $replacement 我们根本没有任何优势:表达式 $replacement 与插值 $replacement

我们需要另一个 /e 吗?这将在第一个 /e 的结果上调用 eval,所以我们要求 eval '\u',并且不会编译,因为 \u 不是一个可行的 Perl程序,所以 eval returns undef 我们得到

Use of uninitialized value in substitution iterator

解决办法是把$replacement做成可编译的程序。在它周围加上双引号,例如 "\u" 将它变成一个非常短的 Perl 程序,其中 returns </code> 的当前值,第一个字符大写 </p> <p>我们需要将 <code>$replacement 设置为该字符串,包括双引号并避免像以前一样处理转义字符和 </code>。如果我写</p> <pre><code>my $replacement = '"\u"';

然后我得到了字符串 "\u" 包括双引号

现在让我们试试

use strict;
use warnings 'all';

my $regex       = '^(\w)';
my $replacement = '"\u"';

my @array = ('one two three', 'green blue red');

s/$regex/$replacement/eeg for @array;

print "$_\n" for @array;

输出

One two three
Green blue red

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