Perlでforeachを使うときのメモ

Perlのforeachforと同義語だそうです。(*1)
つまり、foreachでもforでも好きな方を使って良いみたいです。

それはさておき、foreachで取得した変数を書き換えたらどうなるんだっけ?
って思って、ちょっと試してみました。

use v5.10;
use strict;
use warnings;

my @foo = qw/a b c/;

{
    my @bar = @foo;
    foreach (@bar) {
        s/[abc]/x/; # $_ =~ s/[abc]/x/;
    }

    say join(',', @foo), ' >>> ', join(',', @bar);
}

{
    my @bar = @foo;
    foreach my $str (@bar) {
        $str =~ s/[abc]/x/;
    }

    say join(',', @foo), ' >>> ', join(',', @bar);
}

{
    my @bar = @foo;
    foreach my $str (@bar) {
        (my $tmp = $str) =~ s/[abc]/x/;
    }

    say join(',', @foo), ' >>> ', join(',', @bar);
}

実行すると、こんな感じ。
$ perl aaa.pl
a,b,c >>> x,x,x
a,b,c >>> x,x,x
a,b,c >>> a,b,c

mapgrepで、$_を書き換えるのは行儀が悪いっていうのは知ってたけど、
for/foreachでもアレですね。

普通に添字を使って書き換えるくらいなら、
上記の方法で書き換えるっていうのでも良いけれど、
だったらmapを使って、変更後の配列を作った方が良い気がします。

use v5.10;
use strict;
use warnings;

my @foo = qw/a b c/;

{
    my @bar = @foo;
    for (my $i=0; $i<scalar(@bar); $i++) {
        $bar[$i] =~ s/[abc]/x/;
    }

    say join(',', @foo), ' >>> ', join(',', @bar);
}

{
    my @bar = @foo;
    @bar = map {
        (my $str = $_) =~ s/[abc]/x/;
        $str;
    } @bar;

    say join(',', @foo), ' >>> ', join(',', @bar);
}

実行すると、こんな感じ。
$ perl bbb.pl
a,b,c >>> x,x,x
a,b,c >>> x,x,x

書き換えてはみたものの、意図が伝わり難いコードになっちゃいました。。。
お題が良くなかったですかねーって思って、
perldoc.jpを眺めてたら良いものを見つけました!

非破壊置換修飾子

s///r(*2)を使うと、こう書ける。

use v5.14; # <<< not v5.10
use strict;
use warnings;

my @foo = qw/a b c/;
my @bar = map { s/[abc]/x/r; } @foo;

say join(',', @foo), ' >>> ', join(',', @bar);

実行すると、こんな感じ。
$ perl ccc.pl
a,b,c >>> x,x,x

おお!これは、便利!!
Perl v5.14.0から入ったみたいですね。

非破壊的置換 – perl v5.14.0 での変更点
http://perldoc.jp/docs/perl/5.14.0/perl5140delta.pod#Non-destructive32substitution

という訳で、ちょっと賢くなりました。

おしまい。

(*1) Perl の文法(perldoc.jp)
(*2) Perl の正規表現のチュートリアル(perldoc.jp)

Leave a Comment