1

かなり規則的で、次のような巨大なテキスト ファイル (約 5 億行のテキスト) を分割しようとしています。

-- Start ---

blah blah

-- End --

-- Start --

blah blah

-- End --

...

どこで ... は繰り返しパターンを意味し、「何とか」は可変長〜2000行です。1人目は別れたい

-- Start --

blah blah

-- End --

別のファイルにブロックし、可能な方法で元のファイルから削除します。

理想的な解決策は、元のファイルから初期ブロックを切り取って、巨大な初期ファイルの末尾をロードせずに新しいファイルに貼り付けることです。

次の方法で csplit を試みました。

csplit file.txt /End/+1 

これは有効な方法ですが、時間的にはあまり効率的ではありません。

編集:最初のブロックではなく最後の「開始-終了」ブロックをファイルから削除すると解決策はありますか?

4

3 に答える 3

6

元のファイルから先頭を削除したい場合は、ファイルの残り全体を読み書きするしかありません。(編集で提案したように)最後を削除するには、はるかに効率的です。

use File::ReadBackwards;
use File::Slurp 'write_file';
my $fh = File::ReadBackwards->new( 'inputfile', "-- End --\n" )
    or die "couldn't read inputfile: $!\n";
my $last_chunk = $fh->readline
    or die "file was empty\n";
my $position = $fh->tell;
$fh->close;
truncate( 'inputfile', $position );
write_file( 'lastchunk', $last_chunk );
于 2014-05-12T06:01:59.050 に答える
2

おそらく、次のようなものが役立ちます。

-- End --マーカーごとにファイルを分割します。単純なインクリメント サフィックスを使用して新しいファイルを作成します。

use strict;
use warnings;
use autodie;

my $file = shift;

my $i = 0;
my $fh;

open my $infh, '<', $file;

while (<$infh>) {
    open $fh, '>', $file . '.' . ++$i if !$fh;
    print $fh $_;
    undef $fh if /^-- END --/;
}

残念ながら、truncateファイルの先頭からデータを削除するのに相当するものはありません。

本当にこれを段階的に実行したい場合はtell、最後に読んだ場所を単純にすることをお勧めします。そうすれば、seek別のファイルを出力する準備ができたときに実行できます。

于 2014-05-12T05:18:06.330 に答える
0

Operator を使用して、flip-flopこのパターン間のコンテンツを取得できます。

use File::Slurp;
my @text = read_file( 'filename' ) ;
foreach my $line (@text){
  if ($line =~ /Start/ .. /End/) {
    # do stuff with $line
    print $line; # or so
  }
}

ファイルが大きい場合は、ファイル全体を一度に丸呑みすることに注意してください。

于 2014-05-12T05:11:41.690 に答える