Perl匹配变量和性能.它是如何工作的?

Håk*_*and 4 perl

根据perlvar:

与正则表达式相关的变量

除非另有说明,否则这些变量是只读的和动态范围的.正则表达式变量的动态特性意味着它们的值仅限于它们所在的块.

进一步向下:

传统上,在Perl中,任何使用任何三个变量$`,$&$'在代码的任何地方,造成所有后续成功的模式匹配,使匹配的字符串的一个副本,以防代码可能随后访问这些变量之一.

在阅读文档中的其余部分之后,我仍然遗漏了一些信息,例如:

  • 为什么首先制作副本?

    我想我知道这个问题的答案:从最后一个陈述中可以清楚地看出来"in case the code might subsequently access one of those variables".所以在我的理解中:

    my $s = "Hello world";
    $s =~ s/Hello //;
    say $';
    
    Run Code Online (Sandbox Code Playgroud)

    这仍然会打印,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";
    
    Run Code Online (Sandbox Code Playgroud)

    在这种情况下,(因为$'只在内部范围内使用),没有与一百万个成功匹配相关的复制$s =~ /2/g?(Asumming我没有提到任何一个$`,$&并且$'在外部范围内)


注意:

  • 该问题假设perl版本小于5.18.根据perlvar:

    在Perl 5.18.0以后,perl开始分别注意三个变量中每一个的存在,并且只复制了所需的那部分字符串

    在Perl 5.20.0中,默认情况下启用了一个新的写时复制系统,它最终修复了这三个变量的所有性能问题,并使它们可以安全地在任何地方使用.

  • 出于好奇,我只是问这个问题.我不打算在我的代码中实际使用任何这些变量,因为我希望我的程序能够有效地用于早期的perl版本(<5.20).

    此外,由于手册中,他们可以很容易地使用模拟(不隐复制和性能命中)$+[0]$-[0](这是在Perl 5.6版引入的.我用perl版本5.22自己).有关更多信息,请参阅perlvar.

mel*_*ene 6

  • 它必须复制字符串,因为原始变量可能在正则表达式匹配和使用匹配变量的时间之间被修改:

    my $var = "foobar";
    $var =~ /.../ or die;
    $var = "hello";
    print "$& $'";  # outputs "foo bar"
    
    Run Code Online (Sandbox Code Playgroud)
  • 它有效地使整个字符串的副本,因为这是$` . $& . $'在产生的.当你引述自己,在Perl 5.18有人意识到,你可以分别跟踪每个变量,因此只复制在比赛之前的部分(或比赛本身,或匹配后的部分)如果代码中只出现该变量:

    在Perl 5.18.0以后,perl开始分别注意三个变量中每一个的存在,并且只复制了所需的那部分字符串

  • 匹配变量是全局的.你可以随时调用访问函数(即调用调用的函数等...)$`$&$',所以Perl有每个成功的正则表达式匹配后做一个完整的副本,如果这些变量已经在代码的任何地方看到.(基本上,perl不能静态地确定特定的代码片段永远不会访问那些匹配变量,从而避免复制.)