3

これが私のコードです:

#!perl -w
use strict;

my %hash = (
    1 => "a",
    2 => "b",
);

foreach my $num ( keys %hash ) {
    while (<DATA>) {
        s/$num/$hash{$num}/g;
        print;
    }
}
__DATA__
121212
11111
222 

すべての数値を、ハッシュに存在する対応する値に置き換えるつもりです。しかし、それは出力します:

a2a2a2
aaaaa
222
Hit any key to close this window...

foreachループが1回だけ実行されるのはなぜですか?誰が私にそれを説明できますか?そして、どのようにコードを変更する必要がありますか?出力したい:

ababab
aaaaa
bbb

前もって感謝します。

4

4 に答える 4

5

foreachループが 1 回しか実行されないように見える理由は、一度に<DATA>1 行ずつ読み取っているためです。外側のループを 2 回目にループすると、内側のループのデータから読み取るデータが残っていません。<DATA>代わりに、最初にすべてをリストに読み込んでみませんか:

@mylist = <DATA>

そして、内側のループでこのリストをループします。

于 2012-05-05T08:42:14.847 に答える
1

ハッシュ内の各キーのファイルをループしたり、ファイルを丸呑みしたりする代わりに、ハッシュのキーを1つの検索パターンに組み合わせることができます。

スクリプトの現在のバージョンと@Benjの回答では、キーによって返されるキーの順序がs間で、または同じを使用する異なる実行間でさえ異なる可能性があるため、置換が適用される順序は不確定であることに注意してください。perlperl

つまり、注文を選択し、サプライズが気に入らない限り、それを維持する必要があります。次のスクリプトは、両方のアイデアを組み合わせたものです。ほとんどのコンテキストで意味のある短いキーの前に長いキーを配置することにしました。

#!perl -w
use strict;

my %hash = qw(1 a 11 zz 2 b);

my $pat = join '|', 
          map qr/\Q$_\E/, 
          sort { length $b <=> length $a }
          keys %hash
          ;

while (<DATA>) {
    s/($pat)/$hash{$1}/g;
    print;
}

__DATA__
121212
11111
222 

出力:

アババブ
zzzza
bbb
于 2012-05-05T11:15:04.323 に答える
1

コードの問題は、Benjが指摘していることです。DATAファイルハンドルは、の2回目の反復ではeofにありますforeach。ただし、最初の反復中に値を出力することも必要です。

1つの文字だけを別の文字に置き換える場合、つまりキー/値の長さが1を超えることはない場合は、tr///代わりに使用する必要があると思います。

use strict;
use warnings;

while (<DATA>) {
    tr/12/ab/;
    print;
}

__DATA__
121212
11111
222 

文字変換演算子は、文字列内のすべての文字を一度に置き換えます。1つの問題は、tr///演算子をハードコーディングする必要があるため、文字を動的に切り替えることができないことです。

ハッシュを使用する場合、キー/値が1より長くなる可能性がある場合は、Sinanの注意を払う必要があります。たとえば、キー111、の両方がある場合、どちらが他よりも優先されますか?ただし、1文字の置換の場合、これはスムーズに行う方法です。

my %hash = qw(1 a 2 b);

while (<DATA>) {
    s|(.)| $hash{$1} // $1 |ge;
    print;
}

正規表現修飾子の使用に注意してください/e。これにより、置換によってRHSが評価され、戻り値が挿入されます。この場合、//演算子を使用します。ハッシュ値が定義されているかどうかを確認し、定義されていない場合は、代わりにキーを使用します。に似ている

if (defined $hash{$1}) {
    $hash{$1};
} else {
    $1;
}

または

defined $hash{$1} ? $hash{$1} : $1

また、。を使用すると一度に1文字かかる(.)ため、1文字のキーに対してのみ機能することにも注意してください。

于 2012-05-05T15:36:50.243 に答える
0

最も簡単な答えは、単に のforeachwhileで行うことです。

#!perl -w
use strict;

my %hash = (
    1 => "a",
    2 => "b",
);

while (<DATA>) {
    foreach my $num ( keys %hash ) {
        s/$num/$hash{$num}/g;
    }
    print;
}
__DATA__
121212
11111
222 

他の人が指摘しているように、元のプログラムの問題はDATAファイルハンドルの読み取り位置でした。このrewind関数は通常、ファイルハンドルの位置を最初にリセットして再度読み取ることができるようにするために使用されDATAます。.plファイル自体。ただし、を使用して位置を保存し、次を使用tellして反復ごとにそこに戻すことができseekます。

#!perl -w
use strict;
use Fcntl qw( SEEK_SET );

my %hash = (
    1 => "a",
    2 => "b",
);

my $pos = tell DATA;

foreach my $num ( keys %hash ) {
    seek DATA, $pos, SEEK_SET;
    while (<DATA>) {
        s/$num/$hash{$num}/g;
        print;
    }
}
__DATA__
121212
11111
222 

次の出力が得られます。

a2a2a2
aaaaa
222 
1b1b1b
11111
bbb 
于 2012-05-06T15:51:11.000 に答える