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の勉強を始めたばかりで突っ込み所満載のロジックだとは思いますが、解決策をぜひご教示ください。
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
ご回答をありがとうございました。この手の仕様が厄介だということすら、認識できていませんでした。ご回答の例は、大変わかりやすくてためになりました。活用させていただこうと思います。
No.4
- 回答日時:
出力データをメモリ上にもつ以外の、
「さかのぼって行を削除する方法」に対する他の答えとして・・
一旦、別ファイルに出力しておいて、
最後に別ファイルを元のファイル名にrenameする、
というのも分かりやすいです。
「A~Cの数字が一つでも違った場合、
ハッシュ(一つ前ではない方)から出力ファイルへ書き出す」
という感じですね。
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);
別処理で元ファイルが書き換わる場合は、
排他処理を行わないといけないですね。
意味を判りやすく書こうとするとこんな感じですね。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Excel(エクセル) PowerQueryに詳しい方教えてください(Office365) 1 2022/07/24 21:11
- カスタマイズ(車) 走り屋、峠、ドリ車ベースとしてなぜ歴代ロードスターは不人気なのか? 7 2022/09/20 07:35
- Visual Basic(VBA) 3つのプロシージャをまとめたら実行時エラー発生で対応不能 6 2022/05/17 01:47
- Visual Basic(VBA) vbaのループ処理について 6 2022/05/06 15:35
- Excel(エクセル) エクセルの数式で教えてください。 1 2023/02/02 10:20
- Visual Basic(VBA) Excelにて、シート1の行を削除するとシート2のシート1と同じ番号の行も削除したい 3 2022/05/08 04:24
- Perl perlで2次元配列をサブルーチンに値渡しで渡す 5 2022/12/17 18:49
- Chrome(クローム) 急募 Chromeの不調 1 2023/02/20 20:06
- Visual Basic(VBA) 特定の文字を簡単な操作で半角スペースに変換するか削除したい 2 2022/11/01 10:35
- C言語・C++・C# c言語の問題です 2 2023/07/21 10:51
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
DOSコマンドで、標準出力を出力...
-
CGIから外部コマンド実行時の標...
-
log2の「正確な」計算方法
-
Perlでファイルの末尾から指定...
-
awkスクリプトでダブルクォーテ...
-
fopenでディレクトリ内の全ファ...
-
バッチファイルの作り方(CSV→...
-
vba dir の相対パス
-
batファイルでrenameができませ...
-
VBAコードを張り付け後のエクセ...
-
複数ファイルを1つにするシェ...
-
外部サーバーにあるファイルを...
-
shellのコマンド deffの差分の...
-
VBAでCSVファイルの特定行を書...
-
MATLAB グローバル変数の宣言
-
ListBoxのデータを高速でファイ...
-
Perlで空白行を削除
-
openした後、closeしないでプロ...
-
ADOによるCSVファイルからのデ...
-
Perlで特定行から特定行までを...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
awkスクリプトでダブルクォーテ...
-
DOSコマンドで、標準出力を出力...
-
重複するデータを抽出できる秀...
-
Perlでファイルの末尾から指定...
-
sprintfについて
-
[Perl]ファイル出力のエンコー...
-
エクセルVBAで素数だけを出力す...
-
文字コードの変換(Shift-JISか...
-
テキストファイルから日本語部...
-
sprintfで10進数を桁数指定で16...
-
ファイル出力の改行コードをLFに
-
Perlからsyslog経由でログを出...
-
PerlからのCSV出力
-
perlでcsvの出力について
-
教えて!perlから.exeファイル...
-
バッチファイルで、記号を含む...
-
perl CGIでのhttpヘッダー出力...
-
print文で&(半角)文字のエラー...
-
Perlでエラーログに日時をつける
-
紙にもホームページにも同じレ...
おすすめ情報