根据perlvar:
与正则表达式相关的变量
这些变量是只读的 除非另有说明,否则动态范围。动态性 正则表达式变量意味着它们的值是有限的 他们所在的街区。
并进一步向下:
传统上在Perl中,任何使用三个变量中的任何一个
$`
,$&
或$'
导致代码中的任何地方 所有后续成功的模式匹配,以制作副本 匹配的字符串,以防代码随后访问其中一个 那些变数。
在阅读文档中的其余部分后,我仍然遗漏了一些信息,如:
为什么首先制作副本?
我想我知道这个问题的答案:从上一个陈述"in case the code might subsequently access one of those variables"
可以看出这一点。
所以在我的理解中:
my $s = "Hello world";
$s =~ s/Hello //;
say $';
这仍然会打印world
,因为在修改$s
之前制作了副本。
为什么要完成整个字符串的副本?
在前面的示例中,只复制字符串的尾部部分就足够了,因为只使用了$'
(我们没有使用$`
或$&
)。那么为什么要复制整个字符串?
最后:由于它显示"all subsequent"
而不是"all subsequent matches in that block"
,我希望确认:
my $s = "no\n yesHello world";
{
$s =~ /yes/ and say $'; # Note the use of $'
}
$s = '12' x 1_000_000;
my $n = () = $s =~ /2/g;
say "Found $n matches";
在这种情况下,(因为$'
仅在内部范围内使用),与$s =~ /2/g
中的一百万个成功匹配没有相关的复制? (Asumming我没有在外部范围内提及任何$`
,$&
和$'
注意:
该问题假定perl版本小于5.18。 根据{{3}}:
在Perl 5.18.0之后,perl开始注意到每个的存在 三个变量分开,只复制那部分 需要字符串
在Perl 5.20.0中,默认启用了一个新的写时复制系统, 最终修复了这三个变量的所有性能问题, 并使它们可以安全地在任何地方使用。
我只是出于好奇而问这个问题。我并不打算在我的代码中实际使用任何这些变量,因为我希望我的程序能够有效地用于早期的perl版本(< 5.20)。
此外,如手册中所述,可以使用$+[0]
和$-[0]
(在perl 5.6版中引入)轻松模拟它们(没有隐式复制和性能命中)。我使用的是perl版本5.22我自己)。有关详细信息,请参阅perlvar。
答案 0 :(得分:6)
必须复制字符串,因为原始变量可能在正则表达式匹配和使用匹配变量的时间之间被修改:
my $var = "foobar";
$var =~ /.../ or die;
$var = "hello";
print "$& $'"; # outputs "foo bar"
它必须有效地制作整个字符串的副本,因为$` . $& . $'
导致的结果。正如你自己引用的那样,在perl 5.18中,有人意识到你可以分别跟踪每个变量。因此,如果代码中只出现该变量,则只复制匹配前的部分(或匹配本身或匹配后的部分):
在Perl 5.18.0以后,perl开始分别注意三个变量中每一个的存在,并且只复制了所需字符串的那部分
匹配变量是全局的。您可以随时调用访问$`
或$&
或$'
的函数(调用函数调用函数...),因此perl必须在完成后才能完整复制每个成功的正则表达式匹配,如果在代码中的任何地方都看到了这些变量。 (基本上,perl可以静态地确定某段代码永远不会访问这些匹配变量,从而避免复制。)