regex Perl -意外行为:如果迭代器$r通过正则表达式改变,则遍历数组“foreach $r(@a)”-数组元素本身也改变了

8xiog9wr  于 2023-04-22  发布在  Perl
关注(0)|答案(1)|浏览(92)
sub summs_by_key {
    foreach my $R (@CURR_RECS) {    
        if ($combine) {
            print __LINE__ . ") ... $R" ; 
            $R =~ s/\^/\|/  for 1 .. $KEY_POS ; # the regex expression
            print __LINE__ . ") ___ $R" ; 
        }
        #... etc 
    }
    #... etc // no other reassingments of $R 
}

注意:@Curr_RECS是一个声明为our @CURR_RECS ;的全局数组,它在一个单独的sub/函数中填充。regex的更改实际上可以更改数组的值。该函数被调用多次,在随后的调用中,regex的更改会被注意到已经作用于数组的元素。
我的问题是,这是正常行为还是Perl错误-它只发生在正则表达式行执行2次时,而不是一次(即$KEY_POS = 2)
我没有直接使用迭代器,而是使用它的“副本”来修复这个问题。我将迭代器重命名为$Rs,并将其赋值给$R。

foreach my $Rs (@CURR_RECS) {
        my $R = $Rs ;
        if ($combine) {
            print __LINE__ . ") ... $R" ; 
            $R =~ s/\^/\|/  for 1 .. $KEY_POS ;
            print __LINE__ . ") ___ $R" ; 
        }
        # ... etc 
}

@Curr_RECS包含

2x^szo_p^230414:01:43^0^0^
3x^cold^230309p^0^0^QQ.y
3x^szo_p^230419:14:51^-10^6^
4x^cold^230320^0^60^
4x^front^230418:16:36^20^40^
4x^sky^230403^0^0^
4x^szo_r^230419:14:46^-5^23^
6g^szo_p^230309^0^8^
6x^cup^230417:05:04^2^4^
6x^r_l^230402^0^40^

其中插入符号是字段分隔符标记。如果$合并为true,那么我们希望组合前几个字段......这就是正则表达式所完成的......通过将这么多($KEY_POS)分隔符更改为其他内容-进入“|“。这些是正则表达式之前和之后的条目:

125) ... 2m^szo_p^230411:15:01^0^0^
127) ___ 2m|szo_p|230411:15:01|0^0^
125) ... 2x^szo_p^230414:01:43^0^0^
127) ___ 2x|szo_p|230414:01:43|0^0^
125) ... 3x^cold^230309p^0^0^QQ.y
127) ___ 3x|cold|230309p|0^0^QQ.y
125) ... 3x^szo_p^230419:14:51^-10^6^
127) ___ 3x|szo_p|230419:14:51|-10^6^

然而,当同一个函数再次执行时,传入的元素与第一次运行时不一样......但是已经根据正则表达式进行了修改。前导126) ...127) ___不是数组的一部分,它们是代码的LINE号。在第二次调用函数时,我们可以看到传入的元素显示了先前调用移动的插入符号。

121) ... 2m|szo_p|230411:15:01|0^0^
123) ___ 2m|szo_p|230411:15:01|0|0|
Use of uninitialized value $V in addition (+) at /media/pk/u2win/dev/pkp.db/pkp.summ.pl line 132.
121) ... 2x|szo_p|230414:01:43|0^0^
123) ___ 2x|szo_p|230414:01:43|0|0|
Use of uninitialized value $V in addition (+) at /media/pk/u2win/dev/pkp.db/pkp.summ.pl line 132.
zvms9eto

zvms9eto1#

perlsyn:
如果LIST的任何元素是左值,则可以通过在循环内修改VAR来修改它。相反,如果LIST的任何元素不是左值,则任何修改该元素的尝试都将失败。换句话说,foreach循环索引变量是您正在循环的列表中每个项目的隐式别名。
所以是的,循环迭代器不是副本,而是别名。

my @a = 1..3;
++$_ for @a;
say "@a";  # "2 3 4"

下面是一个稍微简单的复制方法:

for ( @CURR_RECS ) {
   my $R = $_;
   ...
}

以下是另一种方法,但您可能应该避免,因为它的作用并不明显:

for my $R ( map $_, @CURR_RECS ) {
   ...
}

你也可以避免复制。

my $R2 = join "|", split /\^/, $R, $KEY_POS+1;
print __LINE__ . ") ___ $R2";

当然也比多次替换要快。

相关问题