代码之家  ›  专栏  ›  技术社区  ›  j_random_hacker

有没有一种简单的方法来本地化(保存)所有“魔法变量”,如$1,$等?

  •  9
  • j_random_hacker  · 技术社区  · 15 年前

    我知道在Perl的子例程中,最好保留“默认变量” $_ 具有 local 在对其进行任何操作之前,如果呼叫者正在使用它,例如:

    sub f() {
        local $_;              # Ensure $_ is restored on dynamic scope exit
        while (<$somefile>) {  # Clobbers $_, but that's OK -- it will be restored
            ...
        }
    }
    

    现在,经常是你使用的原因 美元 首先是因为您希望使用regex,这可能会将结果放在方便的“magic”变量中,比如 $1 , $2 等。 我也想保留这些变量,但我还没有找到一种方法。

    Perlvar只说 @+ @- 哪一个 1美元 等。似乎依赖于内部,参考“当前活动动态范围内最后一次成功的子匹配”。但即便如此,我的实验似乎也不一致。根据经验,以下代码按我所希望的方式打印“axaa”:

    $_ = 'a';
    /(.)/;          # Sets $1 to 'a'
    print $1;       # Prints 'a'
    {
        local $_;   # Preserve $_
        $_ = 'X';
        /(.)/;      # Sets $1 to 'X'
        print $1;   # Prints 'X'
    }
    print $_;       # Prints 'a' ('local' restored the earlier value of $_)
    print $1;       # Prints 'a', suggesting localising $_ does localise $1 etc. too
    

    但我真正感到惊讶的是,至少在我的ActivePerl5.10.0中, 评论 地方的 线条仍然保留 1美元 --也就是说,生成了答案“axxa”!括号封闭块的词汇(非动态)范围似乎在某种程度上保留了 1美元 .

    所以我觉得这种情况充其量是令人困惑的,我希望听到一个明确的解释。提醒你,我已经决定用一种防弹的方法来保护 全部的 与regex相关的魔力变量,无需枚举它们,如:

    local @+, @-, $&, $1, $2, $3, $4, ...
    

    这显然是一个恶心的黑客。在那之前,我会担心我接触到的任何regex都会击倒来电者不希望被击倒的东西。

    谢谢!

    3 回复  |  直到 15 年前
        1
  •  8
  •   ysth    15 年前

    也许您可以为文档建议一个更好的措辞。动态范围是指到封闭块或子例程开始之前的所有内容,加上到块或子例程调用开始之前的所有内容,等等。 除了 排除任何闭合块。

    另一种说法是:“当前活动动态范围内最后一次成功的子匹配”意味着 local $x=$x; 在每个变量的每个块的开头。

    大多数提到的动态范围(例如, http://perldoc.perl.org/perlglossary.html#scope http://perldoc.perl.org/perlglossary.html#dynamic-scoping ) 从另一个方向接近它。如果你认为一个成功的人 regex as隐式执行 local $1 等。

        2
  •  3
  •   Sinan Ünür    15 年前

    我不确定有什么真正的理由对所有这些变量如此偏执。我已经使用Perl近十年了,不需要使用显式的 local 在这种情况下。

    您具体问题的答案是:数字变量的数量不是给定的(即使您可以使用的匹配数量有一个硬内存限制)。因此,不可能同时将它们全部本地化。

        3
  •  1
  •   brian d foy JRFerguson    15 年前

    我觉得你太担心了。最好的做法是运行match运算符,立即将所需的值保存到有意义的变量中,然后让特殊变量做它们所做的任何事情而不必担心它们:

    if( $string =~ m/...(a.c).../ ) {
        my $found = $1;
        }
    

    当我想要捕获字符串的一部分时,我经常在列表上下文中使用match操作符来获取内存列表:

    my @array = $string =~ m/..../g;