あるテキストファイルに対して、複数個の置換を一気に行いたい。例えば、こういう置換候補のファイルを用意してテキストファイルに適用するとか。
before1 after1 before2 after2 before3 after3
普通に考えるとこういうコードになるでしょう。
use strict; use warnings; my $txtfile = shift; my $repfile = shift; my %replace; open my $fh1, "<", $repfile; while (<$fh1>){ tr/\x0D\x0A//d; my ($k, $v) = split(/\s/); $replace{$k} = $v; } close $fh1; open my $fh2, "<", $txtfile; while(my $line = <$fh2>){ foreach my $k (keys %replace){ $line =~ s/$k/$replace{$k}/g; } print $line; } close $fh2;
ただ、これは遅い・・・。入力ファイルの各行ごとに、置換対象の正規表現をひとつずつコンパイルして適用してるんだから、遅いのも当然でしょう。複数の正規表現を最適化するにはRegexp::Assembleという手もあるみたいだけど、オーバースペックだよなあ。ということで、とりあえずはevalを使ってお手軽に解決することにしました。$repfileの読み込みが終わった後の処理を
my $re = eval 'qr/(' . join('|', keys %replace) . ')/'; open my $fh2, "<", $txtfile; while(my $line = <$fh2>){ $line =~ s/$re/$replace{$1}/go; print $line; } close $fh2;
こんな感じにする。
テキストファイルが1500行ほど、置換候補が20個ほどの入力で試してみる。
$ time perl rep.pl txtfile repfile > /dev/null real 0m0.484s user 0m0.452s sys 0m0.046s $ time perl rep2.pl txtfile repfile > /dev/null real 0m0.078s user 0m0.046s sys 0m0.046s
6倍強早くなる。この程度のinputでこれだけ目に見えて早くなるもんですなあ。正規表現のオーバーヘッドは侮れない。