更新2:解決しました。下記参照。
私は、大きなtxtファイルを古いDOSベースのライブラリプログラムからより使いやすい形式に変換しているところです。私はPerlで始めたばかりで、次のようなスクリプトをまとめることができました。
BEGIN {undef $/; };
open $in, '<', "orig.txt" or die "Can't read old file: $!";
open $out, '>', "mod.txt" or die "Can't write new file: $!";
while( <$in> )
{
$C=s/foo/bar/gm;
print "$C matches replaced.\n"
etc...
print $out $_;
}
close $out;
非常に高速ですが、しばらくすると常に「メモリ不足」が発生します-RAM /スワップスペースが不足しているためエラーが発生します(2GBのRAMと1.5GBのスワップファイルを搭載したWin XPを使用しています)。大きなファイルを処理する方法を少し調べた後、File::Map
この問題を回避するための良い方法のように思えました。しかし、私はそれを実装するのに苦労しています。これは私が今持っているものです:
#!perl -w
use strict;
use warnings;
use File::Map qw(map_file);
my $out = 'output.txt';
map_file my $map, 'input.txt', '<';
$map =~ s/foo/bar/gm;
print $out $map;
ただし、次のエラーが発生します。Modification of a read-only value attempted at gott.pl line 8.
また、File::Map
ヘルプページで、Unix以外のシステムで使用する必要があることを読みましたbinmode
。それ、どうやったら出来るの?
基本的に、私がやりたいのは、File :: Mapを介してファイルを「ロード」してから、次のようなコードを実行することです。
$C=s/foo/bar/gm;
print "$C matches found and replaced.\n"
$C=s/goo/far/gm;
print "$C matches found and replaced.\n"
while(m/complex_condition/gm)
{
$C=s/complex/regex/gm;
$run_counter++;
}
print "$C matches replaced. Script looped $run_counter times.\n";
etc...
あまりにも明白なことを見落としていないことを願っていますが、File::Map
ヘルプページに示されている例は、マップされたファイルから読み取る方法を示しているだけですよね?
編集:
メモリ不足のために現在達成できないことをよりよく説明するために、例を示します。
http://pastebin.com/6Ehnx6xAには、エクスポートされたライブラリレコード(txt形式)の1つのサンプルがあります。46行目から始まる部分に興味があり+Deskriptoren:
ます。これらは、ツリー階層で編成された主題分類子です。
私が欲しいのは、親ノードの完全なチェーンで各分類子を拡張することですが、問題の子ノードの前後に親ノードがまだ存在しない場合に限ります。これは回転することを意味します
+Deskriptoren
-foo
-Cultural Revolution
-bar
の中へ
+Deskriptoren
-foo
-History
-Modern History
-PRC
-Cultural Revolution
-bar
現在使用されている正規表現は、重複の重複を避けるためにLookbehindとLookaheadを使用するため、以下よりも少し複雑ですs/foo/bar/g;
。
s/(?<=\+Deskriptoren:\n)((?:-(?!\QParent-Node\E).+\n)*)-(Child-Node_1|Child-Node_2|...|Child-Node_11)\n((?:-(?!Parent-Node).+\n)*)/${1}-Parent-Node\n-${2}\n${3}/g;
しかし、それは機能します!Perlがメモリを使い果たすまで...:/
したがって、本質的には、大きなファイル(80MB)を数行にわたって操作する方法が必要です。処理時間は問題ではありません。これが私がFile::Mapを考えた理由です。別のオプションとして、リンクされたperlスクリプトを使用してファイルをいくつかのステップで処理し、相互に呼び出して終了することもできますが、できるだけ1か所に保管したいと思います。
更新2:
以下のSchwelmのコードでなんとか動作させることができました。私のスクリプトは、2つのネストされたサブルーチンを呼び出す次のサブルーチンを呼び出します。サンプルコードは次の場所にあります:http://pastebin.com/SQd2f8ZZ
私が仕事に就けなかったことにまだ完全には満足していませんFile::Map
。まあ...とにかくラインアプローチの方が効率的だと思います。
みんな、ありがとう!