web-dev-qa-db-ja.com

ファイルの途中の行をPerlで置き換えるにはどうすればよいですか?

追加モードでファイルを開いています。ファイルの2、3、4行目を置き換える必要があります。後で、ファイルの最後に新しいデータを追加する必要があります。

19
kkchaitu

これはFAQ Stackoverflowに最も多く投稿した回答です。 perlfaq5変更、削除、または、ファイルに行を挿入するか、ファイルの先頭に追加しますか?

追加モードのことは忘れてください。それはあなたの人生をより困難にするでしょう。


テキストファイルから行を挿入、変更、または削除する基本的な考え方は、変更を加えたいポイントまでファイルを読み取って印刷し、変更を加えてから、残りのファイルを読み取って印刷することです。 Tie :: File などのモジュールはそれを偽ることができますが、Perlは行へのランダムアクセスを提供しません(特に、レコード入力区切り記号$/は変更可能であるため)。

これらのタスクを実行するPerlプログラムは、ファイルを開き、その行を印刷してからファイルを閉じるという基本的な形式をとります。

open my $in,  '<',  $file      or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";

while( <$in> )
    {
    print $out $_;
    }

close $out;

その基本的なフォーム内で、行の挿入、変更、または削除に必要なパーツを追加します。

行を先頭に追加するには、既存の行を印刷するループに入る前に、それらの行を印刷します。

open my $in,  '<',  $file      or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";

print $out "# Add this line to the top\n"; # <--- HERE'S THE MAGIC

while( <$in> )
    {
    print $out $_;
    }

close $out;

既存の行を変更するには、whileループ内の行を変更するコードを挿入します。この場合、コードは「Perl」のすべての小文字バージョンを検出し、それらを大文字にします。これはすべての行で発生するので、必ずすべての行で実行するようにしてください。

open my $in,  '<',  $file      or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";

print $out "# Add this line to the top\n";

while( <$in> )
    {
    s/\b(Perl)\b/Perl/g;
    print $out $_;
    }

close $out;

特定の行のみを変更するには、 入力行番号$. が便利です。まず、変更したい行まで読み取り、印刷します。次に、変更する1行を読み取り、変更して、印刷します。その後、残りの行を読み、それらを印刷します。

while( <$in> )   # print the lines before the change
    {
    print $out $_;
    last if $. == 4; # line number before change
    }

my $line = <$in>;
$line =~ s/\b(Perl)\b/Perl/g;
print $out $line;

while( <$in> )   # print the rest of the lines
    {
    print $out $_;
    }

行をスキップするには、ループコントロールを使用します。この例の次の行はコメント行をスキップし、最後の行は__END__または__DATA__に遭遇するとすべての処理を停止します。

while( <$in> )
    {
    next if /^\s+#/;             # skip comment lines
    last if /^__(END|DATA)__$/;  # stop at end of code marker
    print $out $_;
    }

同じように特定の行を削除するには、nextを使用して、出力に表示したくない行をスキップします。この例では、5行ごとにスキップします。

while( <$in> )
    {
    next unless $. % 5;
    print $out $_;
    }

何らかの奇妙な理由で、行ごとに処理するのではなく、ファイル全体を一度に本当に見たい場合は、それをスラップすることができます(すべてをメモリに収めることができる限り)。

open my $in,  '<',  $file      or die "Can't read old file: $!"
open my $out, '>', "$file.new" or die "Can't write new file: $!";

my @lines = do { local $/; <$in> }; # Slurp!

    # do your magic here

print $out @lines;

File :: SlurpTie :: File などのモジュールもこれに役立ちます。ただし、ファイル全体を一度に読み取ることはできません。 Perlは、プロセスが終了するまで、そのメモリをオペレーティングシステムに戻しません。

また、Perlワンライナーを使用して、ファイルをインプレースで変更することもできます。以下は、すべての 'Fred' 'Barney'ininFile.txt、新しい内容でファイルを上書きします。 -pスイッチを使用すると、Perlは-eで指定したコードをwhileループでラップし、-iはインプレース編集をオンにします。現在の行は$_にあります。 -pを使用すると、Perlはループの最後に$_の値を自動的に出力します。詳細は perlrun を参照してください。

Perl -pi -e 's/Fred/Barney/' inFile.txt

InFile.txtのバックアップを作成するには、追加するファイル拡張子を-iに指定します。

Perl -pi.bak -e 's/Fred/Barney/' inFile.txt

5行目のみを変更するには、テストチェック$.、入力行番号を追加し、テストに合格した場合にのみ操作を実行します。

Perl -pi -e 's/Fred/Barney/ if $. == 5' inFile.txt

特定の行の前に行を追加するには、Perlが$_を出力する前に行を追加できます。

Perl -pi -e 'print "Put before third line\n" if $. == 3' inFile.txt

現在の行はループの最後に出力されるため、ファイルの先頭に行を追加することもできます。

Perl -pi -e 'print "Put before first line\n" if $. == 1' inFile.txt

ファイル内の既存の行の後に行を挿入するには、-nスイッチを使用します。ループの最後に-pを出力しないことを除いて、$_と同じなので、自分で行う必要があります。この場合、最初に$_を印刷してから、追加する行を印刷します。

Perl -ni -e 'print; print "Put after fifth line\n" if $. == 5' inFile.txt

行を削除するには、必要な行のみを印刷します。

Perl -ni -e 'print unless /d/' inFile.txt

    ... or ...

Perl -pi -e 'next unless /d/' inFile.txt
40
brian d foy

Tie :: File でこれを行うことができます。 (最初の行を置き換えるためにファイル全体を書き換える必要があることに注意してください。ただし、Tie :: Fileは詳細を非表示にします。)

4
cjm

Perlの優れたイディオムは、標準入出力の読み取りと書き込みです。必要に応じてパイプしてリダイレクトできます。演算子 <> (readlineへのラップ)を介して、Perlはコマンドラインで引数として渡したファイルを開きます。

あなたの質問に答えるために、数行のコード(可能な限りクリーン):

#!/usr/bin/env Perl
use strict; use warnings;

while (<>) {
  if ($. == 2) {
    print "new data", "\n";
    next;
  }
  if ($. == 3) {
    print "very new data", "\n";
    next;
  }
  print;
}

print "more data", "\n"; 

次に、次のように呼び出します:Perl yourscript.pl inputfile> outputfile

ファイルを自分で開きたい場合(ここでは単に不要な行をスキップします):

my open $in_fh, '<', $inputfile
  or die "Can't open file $inputfile: $!";

my open $out_fh, '>', $outputfile
  or die "Can't open file $output: $!";

while (my $line = <$in_fh>) {
  next if ( $. == 2 or $. == 3 or $. == 4 );
  print $out_fh $line;
}
print $out_fh "...whatever\n";
3
i-blis

追加モードでファイルを開いた場合、ファイルを開いたときに既にファイル内にあった行はreplaceできません。ファイルの追加とは、プログラムがファイルを読み取ったり、ファイルの最後に追加したりすることしかできないことを意味します。

新しいファイルを作成し、コンテンツを(おそらく別のファイルのコンテンツに基づいて)追加してから、新しいファイルを別のファイルにコピーできます。

割り当てがよくわかりません。

0
Larry K