プロが教えるわが家の防犯対策術!

CSV形式でデータdata.csvが書いてあります。プログラムを実行して、そのファイルの$data[4]の値が5という数字だった場合は、そこのセルだけ"解除"という文字に置き換えて(ほかに入ってる値ははそのまま)data.csvに上書きしたいのですが、どうもうまくいきません。したのように記述したのですが、どこが間違っているのかがわかりません。。どなたか教えてください。よろしくおねがいします。

#!/usr/bin/perl

$file='data.csv';

open(FILE, "$file");

while(<FILE>){

@data = split(/,/, $_);

}
close(FILE);

if($data[4] eq "5"){$data[4] = "解除";}

open(OUT, ">$file");
print OUT @data;
close(OUT);

A 回答 (6件)

=notes



-- BLUEPIXY さん wrote --
> 名前の書き換えができれば、
> もう一度読み出し書き出したりする必要はありません

アドバイスありがとうございます。
確かに以下のほうがすっきりします。

でも、このページはインデントが効かないのでコードが読みづらいですね。
<td>に<pre>指定か何かをしてくれると有難いですが・・
と、これは管理人さんに言うことですね。

=cut

### 使用ファイル
my $file_1 = "./test/date_1.csv";
my $file_2 = "./test/date_2.csv";

### csvを編集しながら作業ファイルに書き出す
open FILE_1, "<$file_1" or die( "can't open $file_1" );
open FILE_2, ">$file_2" or die( "can't open $file_2" );
while(<FILE_1>){
my @data = split /,/;
$data[4] = '解除' if $data[4] eq '5';
print FILE_2 join( ',', @data );
}
close FILE_1;
close FILE_2;

### 作業ファイルを元のファイルにリネーム
unlink $file_1;
rename $file_2, $file_1;
    • good
    • 0

>でもwhileはループだから全部の行を読むまでループすると思っていました


全部の行を読みますが、その時その時の1行しか処理してないですよね、あとからまとめて書き出すつもりなら、全部の行をとっておかなくちゃね。
#3の方法は、一気にメモリに読み込む方法です。
ファイルが小さいかメモリに余裕があれば良い方法です。
ファイルの大きさが処理前にはわからないとか大きい場合は、
#4さんのように、一行ずつ処理して書き出して、
名前を書き換え元のファイルを消すのが常套手段になります。
(名前の書き換えができれば、もう一度読み出し書き出したりする必要はありません)
    • good
    • 0

=notes



単純なcsvファイルとして、どっこらしょとヒジョー!に単純に書
くとこうなりますでしょうか?
csvの操作にはText::CSV_XSというモジュールが早くて便利です。
・・標準モジュールではないのでDLする必要があります。
また、csvファイルをデータベースとして操作できるモジュールも
ありますので調べて見てください。

=cut

### 使用ファイル
my $file_1 = "./test/date_1.csv";
my $file_2 = "./test/date_2.csv";

### csvを編集しながら作業ファイルに書き出す
open FILE_1, "<$file_1" or die( "can't open $file_1" );
open FILE_2, ">$file_2" or die( "can't open $file_2" );
while(<FILE_1>){
my @data = split /,/;
$data[4] = '解除' if $data[4] eq '5';
print FILE_2 join( ',', @data );
}
close FILE_1;
close FILE_2;

### 元のファイルに書き戻す
open FILE_2, "<$file_2" or die( "can't open $file_2" );
open FILE_1, ">$file_1" or die( "can't open $file_1" );
while(<FILE_2>){
print FILE_1;
}
close FILE_2;
close FILE_1;

### 作業ファイルを削除する
unlink $file_2;
    • good
    • 0

#例えば、こんな風にすればいいです。


$file='data.csv';
open(FILE, "$file");
@data=<FILE>;
close(FILE);
for(@data){
@field = split /,/ ;
$field[4] = "解除" if($field[4] eq "5");
$_=join(",",@field);
}

open(OUT, ">$file");
print OUT @data;
close(OUT);
    • good
    • 0

while(<FILE>){


@data = split(/,/, $_);
}
では、@dataは、一行毎の処理ですから、一行分しか残りません
だから
>if($data[4] eq "5"){$data[4] = "解除";}
は、最後のデータを作業しているだけで
>print OUT @data;
は、最後のデータしか出力しません

この回答への補足

ありがとうございます。おっしゃるとおり、最後のデータしか上書きされませんでした。でもwhileはループだから全部の行を読むまでループすると思っていました。自分もwhileの部分があやしいなあと思っていました。全部の行を読み込むのにはどうしたらいいんですか?ほかに検討がつかなくって。。

補足日時:2005/12/05 19:01
    • good
    • 0

実行した後のdata.csvの内容はどうなっているのですか??

この回答への補足

お返事ありがとうございます。

例えば、CSVの各セルに

123456
123456
123456
123456

上のように数字が入ってるとします。1つの数字が一つのセルに入ってると思ってください。プログラムを実行すると同じファイルの

123456
123456
123456
123456

の4列目に5という数字が入っていたら”解除”という漢字におきかえたいのです。例は同じ数字が縦にならんでいますが、実際はランダム数字です。でじ¥、実行後は

1234解除6
1234解除6
1234解除6
1234解除6

となるように同じファイルに上書きしたいのです。
こういう感じですが、できますでしょうか?よろしくおねがいします。

補足日時:2005/12/05 18:26
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!