0

私は、興味のあるものを見つけたときにファイルオフセットを保存するテキストファイル(UNIXまたはWindowsの行末である可能性があります)を分析するPerlスクリプトを持っています。

open(my $fh, $filename);
my $groups;
my %hash;
while(<$fh>) {
   if($_ =~ /interesting/ ) {
      $hash{$groups++}{offset} = tell($fh);
   }
}
close $fh;

その後、スクリプトの後半で、テキスト ファイルの「n」個のコピーを作成しますが、各「興味深い」領域に追加のコンテンツを追加します。これを実現するために、オフセットのハッシュをループします。

foreach my $group (keys %hash) {
   my $href = $hash{$group};
   my $offset = $href->{offset};

   my $top;
   open( $fh, $file);
   read( $fh, $top, $offset);
   my $bottom = do{local $/; <$fh>};
   close $fh;

   $href->{modified} = $top . "Hello World\n" . $bottom;
}

問題は、読み取りコマンドが読み取っているバイト数が多すぎることです。バイト数(文字?)が行番号と同じであるため、これは行末の問題であると思われます。Notepad ++を使用すると、tell()コマンドは実際のオフセットを対象のポイントに返しますが、そのオフセット値を使用すると、対象read()のポイントを過ぎた文字が返されます。

の前のコマンドbinmode($fh)の直後に追加しようとしました。これにより、テキスト ファイル内の正しい位置が検出されますが、(CR + CRLF) 出力が得られ、テキスト ファイルは二重のキャリッジ リターンでいっぱいになります。open()read()

レイヤー :crlf、:bytes で遊んだことがありますが、改善はありません。

ちょっと立ち往生!

4

3 に答える 3

0

からperldoc -f read:

read FILEHANDLE,SCALAR,LENGTH,OFFSET
read FILEHANDLE,SCALAR,LENGTH

だから、あなたがするとき:

read( $fh, $top, $offset);

あなた$offsetは実際には長さです。何文字読む必要があるかを決めます。 read行末を考慮せず、指定されたバイト数を読み取ります。

行を読みたい場合は、を使用せずに次を使用readします。

seek($fh, $offset, 0);
$top = <$fh>;

あなたのファイルは 2 つの改行でいっぱいですか、printそれともステートメントで 1 つ追加していますか?

于 2013-05-29T13:33:23.710 に答える
0

入力ファイルが巨大でない場合、これを処理する私の標準的な方法は、ファイルを丸呑みして行末を正規化し、各行を配列要素として保存することです。ファイルの同じバッチで、 Windows ( CR+ LF) と UNIX (LFのみ) と Mac (CRのみ) の行末を処理する必要がある場合があります。3 つのプラットフォームすべてで同じスクリプトを正しく実行する必要もあります。

そのようなことに対処しなければならないとき、私は通常、ベルトとブレースのアプローチを取ります. うまくいくはずの1つの方法:

sub read_file_into_array
{
    my $file = shift;
    my ($len, $cnt, $data, @file);

    open my $fh, "<", $file         or die "Can't read $file: $!";
    seek $fh, 0, 2                  or die "Can't seek $file: $!";
    $len = tell $fh;
    seek $fh, 0, 0                  or die "Can't seek $file: $!";

    $cnt = read $fh, $data, $len;
    close $fh;

    $cnt == $len or die "Attempted to read $len bytes; got $cnt";

    $data =~ s/\r\n/\n/g;       # Convert DOS line endings to UNIX
    $data =~ s/\r/\n/g;         # Convert Mac line endings to UNIX

    @file = split /\n/, $data;  # Split on UNIX line endings

    return \@file;
}

次に、 の行ですべての処理を行います@file。「興味深い」タグの場合、ファイル オフセットではなく配列インデックスを保存します。配列インデックスは基本的に元のファイルの行番号であり、1 ではなく 0 から数えます。

実際にファイルを拡張するには、ハッシュ キーをループする代わりに、line-number => thing-to-append ペアで構成されるハッシュを構築して、次のような拡張ファイルを生成してみませんか。

sub generate_augmented_file
{
    my $file   = shift @_;   # array ref
    my $extras = shift @_;   # hash ref of line => extra pairs
    my $text;        

    foreach my $line ( 0 .. scalar( $file ) - 1 )
    {
        $text .= $file->[$line];
        $text .= $extras->{$line} if defined $extras->{$line};
        $text .= "\n";
    }

    return $text;
}
于 2013-06-09T18:21:52.477 に答える