• ベストアンサー

Perlで行をさかのぼって削除する方法を教えて下さい

ActivePerl5.8.4にて、以下の規則に従い、テキストファイルから複数行を削除しようとしています。 ・1つの行はアルファベットと数字から成っており、アルファベットはA,B,Cの順に出現する。A,B,Cの行で一かたまり。 ・数字部分が全く同じかたまりが出現すると、後で出現したかたまりを削除する。 ・数字部分が全く同じかたまりが出現するときは、必ず連続で出現する。 下のような感じです。(スペースの都合で「\n」をつけましたが、実際には改行までが1行に書かれているテキストファイルを読み込みます。) 【入力】 A 1\nB 2\nC 3\nA 1\nB 2\nC 3\nA 1\nB 2\nC 2[EOF] 【出力】 A 1\nB 2\nC 3\nA 1\nB 2\nC 2[EOF] すぐに思いついた方法はこんな感じです(まだ勉強不足のため、コードではあらわせません)。  1.ファイルの1行ずつ読み込む  2.A,B,Cをキーにして数字をハッシュに格納  3.2回目のCまで読み込んだところで1つ前のハッシュと比較  4.AからCの数字がすべて同じだった場合に、現在の行(2つめのCを読み込んでいる)とその前2行を削除(実際にはnextでprintを飛ばす) ところが、4の、さかのぼって行を削除する方法が思いつきません。 なにぶんperlの勉強を始めたばかりで突っ込み所満載のロジックだとは思いますが、解決策をぜひご教示ください。

  • aneja
  • お礼率93% (379/405)
  • Perl
  • 回答数4
  • ありがとう数4

質問者が選んだベストアンサー

  • ベストアンサー
  • guci-ok
  • ベストアンサー率33% (49/146)
回答No.2

テキストファイルというのは、途中を更新したり削除したりするものじゃないんです。 どのような経緯で、そのような厄介なことになってしまったのかわかりませんが、 テキストファイルを無理に使おうとした弊害だと思います。 テキストファイルを全部読んで、処理をし、そして書き戻すのが簡単だと思います。 D:>test1.pl step1: $rec = 'A 1,B 2,C 3,A 1,B 2,C 3,A 1,B 2,C 2,A 3,B 3,C  3,A 3,B 3,C 3,A 3,B 3,C 4,' step2: $rec = 'A 1,B 2,C 3,A 1,B 2,C 2,A 3,B 3,C 3,A 3,B 3,C 4,' --out-- A 1 B 2 C 3 A 1 B 2 C 2 A 3 B 3 C 3 A 3 B 3 C 4 D:> #!Perl use strict; #【入力】 my @rec = <DATA>; chomp @rec; my $rec = join(',' => @rec) . ","; print "step1: \$rec = '$rec'\n"; # データが正しいかチェック die "data in disorder!\n" unless $rec =~ /^(A \d+,B \d+,C \d+,)+$/; # データを処理, 連続するデータはひとつに $rec =~ s/(A \d+,B \d+,C \d+,)\1+/$1/g; print "step2: \$rec = '$rec'\n"; #【出力】 $rec =~ s/,/\n/g; chomp $rec; # 最後の,を削除 print "--out--\n"; print $rec; __DATA__ A 1 B 2 C 3 A 1 B 2 C 3 A 1 B 2 C 2 A 3 B 3 C 3 A 3 B 3 C 3 A 3 B 3 C 4

aneja
質問者

お礼

ご回答をありがとうございました。この手の仕様が厄介だということすら、認識できていませんでした。ご回答の例は、大変わかりやすくてためになりました。活用させていただこうと思います。

その他の回答 (3)

  • thatsthat
  • ベストアンサー率55% (15/27)
回答No.4

出力データをメモリ上にもつ以外の、 「さかのぼって行を削除する方法」に対する他の答えとして・・ 一旦、別ファイルに出力しておいて、 最後に別ファイルを元のファイル名にrenameする、 というのも分かりやすいです。 「A~Cの数字が一つでも違った場合、  ハッシュ(一つ前ではない方)から出力ファイルへ書き出す」 という感じですね。

aneja
質問者

お礼

ご回答ありがとうございました。こういうてもありますね。大変参考になりました。

回答No.3

3行ずつ読み込んで、前の3行と比較し出力 $bef = ""; # 前3行 $line= ""; # 現3行 $ans = ""; # 出力用 open(IN,"test.txt"); while(1){ # 3行読み込み$lineに入れる $line = <IN>; $line .= <IN>; $line .= <IN>; if( $line eq "" ){ last; } # 読み込めなければ終了 elsif( $bef eq $line ){ next; } # 前3行と同じなら次の3行へ else { $bef = $line; #前3行に現3行を入れる $ans .= $line; #出力用に現3行を入れる } } close(IN); # 出力 open(OUT,">test.txt"); print OUT $ans; close(OUT); 別処理で元ファイルが書き換わる場合は、 排他処理を行わないといけないですね。 意味を判りやすく書こうとするとこんな感じですね。

aneja
質問者

お礼

ご回答ありがとうございました。複数行の読み込み例を示していただいて、とても参考になりました。

  • tthe_mine
  • ベストアンサー率46% (19/41)
回答No.1

3行ずつ読み込んだ方が簡単に出来ると思いますよ。

aneja
質問者

お礼

ご回答ありがとうございました。3行ずつ読み込めるのですね。もっと勉強いたします。

関連するQ&A

  • perlで、後ろの行を読んで、前の行に書き込むには?

    perl初心者です。 後ろの行を読んで、戻って、指定の行に、書き込む方法が、よくわかりません。 下記のようなファイルを読み込んで ---------------------------- アルファベット= 1A 2B 3C アルファベット= 1A 2B アルファベット= 1A 2B 3C 4D 5E 6F ------------------------------ 下記のように、「アルファベット=」にアルファベットを入れるには、どうしたらいいでしょうか? ------------------------------ アルファベット=ABC 1A 2B 3C アルファベット=AB 1A 2B アルファベット=ABCDEF 1A 2B 3C 4D 5E 6F -------------------------------- よろしくお願い致します。

  • 英字を含まない文字行を削除

    英字を含まない文字行を削除 1491 1492 1493 1494 1495 1496 1497 1498 1499 149A 149B 149C 149D 149E 149F このような16進数が書かれたテキストファイルがあります。 149A 149B 149C 149D 149E 149F このように英字が含まれていない数字のみの行を削除する方法を教えてください。

  • perlでファイルの読み方

    次のような入力ファイルがあったときに、EOFまでのデータを番号1+番号2別にファイルに出力したいのですが、どのようにするのがいいでしょうか? できれば、入力したデータをハッシュか配列にいれてからデータを加工してファイルに出力したいと思っています。 入力ファイル 1.xxx 2.A EOF 1.xxx 2.B EOF 1.xxx 2.A EOF 1.www 2.B 出力ファイル ファイル1 1.xxx 2.A 1.xxx 2.A ファイル2 1.xxx 2.B ファイル3 1.www 2.B

    • ベストアンサー
    • Perl
  • 行を指定して削除する方法PERL

    ある文字を検索して、その行を含む&1行前と2行後ろの行までを削除するスクリプトを書きたいのですが、上手くいきません。 検索して行番号を獲得して、 $rowという変数に入れました。 それをさらに $a :1行前 $b :2行後ろの行番号に格納しました。 問題は削除するところが上手く行きません。 next if で $aから$bの行番号を削除して、と頼んでいるのですが、空のファイルに上書きされてしまいます。 お願いです。この方法で何が間違っているかを教えてください! #!/opt/perl/5.8.0/bin/perl -w print "Content-type: text/html\n\n"; use CGI qw(:standard); use CGI::Carp qw/fatalsToBrowser/; $filename = "../XML/link.xml"; $new = "../XML/link.xsl"; open(FILE, $filename) or die "Can't open `$filename': $!"; while (<FILE>) { if($_ =~ /HRWeb/){ #print "$."; $row = $.; $a = $row-1; $b = $row+2; print "HRWeb delete rows $a through "; } } &delete ($a, $b); sub delete{ open( OLD, "< $filename" ); open( NEW, "> $new" ); while ( <OLD> ) { next if /$a/../$b/; # copy everything but $a through $b print NEW $_; }print "$a deleted $b"; close( OLD ); close( NEW ); rename( $filename, "$filename.orig" ); rename($new, $filename ); }

    • ベストアンサー
    • Perl
  • エクセル削除行を別ファイルへ抽出

    エクセル初心者のため、お教え下さい。 Aファイル(1000行)より、行削除してBファイル(800行)を別ファイルとして保存しました。 削除した200行のデータをCファイルとして保存したいのですが、どうすれば良いでしょうか? ちなみに、Aファイル、Bファイルとも有ります。 どうぞよろしくお願いいたします。

  • FORTRAN ファイルの入出力の方法がわかりません

    メインプログラムを main.dat 入力するファイルを input.txt とします。 input.txtファイル内は A 12 23 B 49 93 C 66 25 ・ ・ ・ と続いてるとします。(数字は同じ数ずつ並んでて、その間にアルファベットがある) この時、2行目~3行目(12と23)、5行目~6行目(49と93)、8行目~9行目(66,25)、・・・・、とそれぞれのアルファベットのグループの数字を読み込んで、別々の出力ファイルを作るにはどうすれば良いかわかりません。つまり ファイルA 12 23 ファイルB 49 93 ファイルC 66 25 ファイルD ・ ・ ・ とアルファベットのグループ毎にファイルを作りたいのです。 DO文だけでできるのか?また、IF文を使う必要があるのか?直接アクセス入力(ACCESS='DIRECT')を使うのか?初心者でかなり調べたんですがよくわかりません。教えて頂けると幸いです。よろしくお願いします。 また、もしよろしければ、グループCのみの数字(66、25)だけを読み込んで、出力する場合についても教えてくれるとありがたいです。 (基本的なOPEN、READ、WRITE文の使い方はわかっています。)

  • マクロによる条件での行の入力と削除

     初めまして、よろしくお願いします。  次のような二枚のシートがあります  シート1      A  B  C   1     2       ・      99      100 23    101 25   102 31   103 34  104 43  105 44  106 49  107 50  108 55  109 60  110  111  ・  ・  シート2      A  B  C   1     2       ・      99      100 23  1 2 3   101 25  4 5 6 102 31  7 8 9     103 34  0 1 2  104 43  3 4 5     105 44  6 7 8 106 49  9 0 1 107 50  2 3 4 108 55  5 6 7 109 60  8 9 0 110  111  ・  ・ シート1とシート2のA列に入っている数字が通し番号です。シート2では加えてその通し番号のデーター数字がB列、C列、D列に入っています。 のこシート1の通し番号31が削除、代わりに通し番5番と51番を追加し、  シート1      A  B  C   1     2       ・      99      100  5 101 23    102 25     103 34  104 43  105 44  106 49  107 50  108 51 109 55  110 60  111  112  ・  ・ マクロを実行すると  シート2      A  B  C   1     2       ・      99      100  5 101 23  1 2 3   102 25  4 5 6    103 34  0 1 2  104 43  3 4 5     105 44  6 7 8 106 49  9 0 1 107 50  2 3 4 108 51 109 55  5 6 7 110 60  8 9 0 111  112  ・  ・ シート2がこように通し番号31が入っていた行番102行が削除され、新たに通し番5番が行番100に、51番が行番108に挿入追加されるマクロを教えていただきたく、よろしくお願いします。

  • 指定行を取得する方法を教えて下さい。

    変数 $a = "a\nb\nc\nd\ne\nf\ng\n"; としています。 echo $a; の結果をブラウザで表示させてソースを見ると、下記のように意図した通り表示されます。 a b c d e f g この変数 $a の中から3行目("C")だけを取り出したい場合のようにすればよいのでしょうか? よろしくお願い致します。

    • ベストアンサー
    • PHP
  • VBAで色の付いているセルの行削除

    VBAで色の付いているセルの行を削除することは出来ないでしょうか? 量が多すぎて一つ一つ削除すのは大変で間違えて削除してしまいそうなので・・・ - 文字または数字 ■ 色の付いたセル(赤)  A B C D E F・・・ 1- - - - - - 2- - - - - - 3- - - ■ - - 4- - ■ - - - 5- - ■ - - - 6- - - - - - 7- - - ■ - - 8- - ■ - - - 9- - ■ - - - 10- - - - - -       ↓  A B C D E F・・・ 1- - - - - - 2- - - - - - 6- - - - - - 10- - - - - - よろしくお願いします。

  • Excelで、任意の言葉で始まる行のみを、行ごと一括で削除する方法を教

    Excelで、任意の言葉で始まる行のみを、行ごと一括で削除する方法を教えて下さい! 頭から湯気が出そうです... 例えば、下記の場合 A... B... C... B... A... C... A... B... ↓このようにBで始まる行のみ一括で削除したいです A... C... A... C... A... マクロでも関数でも良いので、なるべく簡単な方法を教えてくださいませ よろしくお願い致します

専門家に質問してみよう