• 締切済み

CSVデータの同じファイルに上書きするには。

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);

  • Perl
  • 回答数6
  • ありがとう数6

みんなの回答

  • okiyoshi
  • ベストアンサー率34% (11/32)
回答No.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;

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.5

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

  • okiyoshi
  • ベストアンサー率34% (11/32)
回答No.4

=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;

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.3

#例えば、こんな風にすればいいです。 $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);

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.2

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

satokosan_1999
質問者

補足

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

  • hira6bg
  • ベストアンサー率61% (8/13)
回答No.1

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

satokosan_1999
質問者

補足

お返事ありがとうございます。 例えば、CSVの各セルに 123456 123456 123456 123456 上のように数字が入ってるとします。1つの数字が一つのセルに入ってると思ってください。プログラムを実行すると同じファイルの 123456 123456 123456 123456 の4列目に5という数字が入っていたら”解除”という漢字におきかえたいのです。例は同じ数字が縦にならんでいますが、実際はランダム数字です。でじ¥、実行後は 1234解除6 1234解除6 1234解除6 1234解除6 となるように同じファイルに上書きしたいのです。 こういう感じですが、できますでしょうか?よろしくおねがいします。

関連するQ&A

  • perlでcsvファイルから複数行を抽出したい

    プログラミング初心者です。 お知恵をお貸しください。 perlでcsvファイルから任意の複数行を、コマンドライン引数を使って抜き出したいです。 1行だけだとうまくいきますが、以下ではすべてのcsvデータが出力されてしまいます。 ----------------------getcsv.pl ここから---------------------- #!/usr/bin/perl -- use strict; use warnings; open(IN, "<adata.csv"); open (OUT, ">$bdata.csv"); while(<IN>){ if($. == $ARGV[0] || $ARGV[1] || $ARGV[2] || $ARGV[3]) { print OUT $_; } } close(IN); close (OUT); ----------------------getcsv.pl ここまで---------------------- ----------------------コマンド ここから---------------------- perl getcsv.pl 1 3 8 10 ----------------------コマンド ここまで---------------------- よろしくお願いします。

    • ベストアンサー
    • Perl
  • Perlでのファイル入出力、処理方法

    メモ帳で以下のようなプログラムを書きました。(file_1.plで保存しました) #!/usr/bin/perl $file="data.csv"; $cityfile="name.txt"; $outfile="data_out.csv"; open (IN, $file) or die "$!"; open (FILE, $file) or die "$!"; open (OUT, ">$outfile") or die "$!"; @city = <FILE>; ・ ・ ・ これをCygwinコマンド上で、 perl file_1.pl と入力し、Enterを押すと「No such file or directory at file_1.pl line 9.」と表示されます。 line9はopen (FILE, $file) or die "$!";という文です。 どこが間違えで、どのように修正すればよいのでしょうか。 よろしくお願いします。

  • CSVデータの編集の際の重複チェックの方法

    今、data.csv(カンマ区切り)として、左から順位、名前、性別という3項目で、10人程度のリストデータがあります。 data.csv(カンマ区切り)を編集するようにしていますが、順位は重複してはならないので、重複していたらエラーを出したいのですが。。。 ($rank,$name,$sex) = split(/\,/,$line); です。 open(IN,"$logfile") || &error("ファイルが開けません"); @lines = <IN>; close(IN); # 情報の書換え foreach $line (@lines) { ($rank,$name,$sex) = split(/\,/,$line); $line = "$in{'rank'},$name,$sex\n";} push(@new,$line); } # ファイルを更新 open(OUT,">$logfile") || &error("ファイルが開けません"); print OUT @new; close(OUT);

  • csvデータの開始行と最終行を全体の4分の1で区切り処理をしたい

    csvデータの開始行と最終行を全体の4分の1で区切り処理をしたい csvデータの開始行と最終行を全体の4分の1で区切り処理をしたいと思ってます。 csvファイルは20万件あります。4分の1なので1~50000件となります。 今回は50001~100000件までを行いたいのですが、先日教えていただいたwhile($lines = <IN>) ですと、最初から1件ずつ最終行まで処理をしてしまいます。 (ここから) open(OUT,">$csv"); open(IN,"$data") || &error(" $data を読み込みopen出来ません"); while($lines = <IN>) { ($seq1,$categ,$password,$imail,$cont) = split("\,", $lines); $cont .= " "; $data = "$seq1,$cont,1\n"; print OUT "$data"; $data = ""; } close IN; close OUT; (ここまで) 今回は20万件ですが、毎回このデータ量は月次ごとに変わります。 while周辺をいじるような気がしていますがどのようになるのかがわからなかったので質問いたしました。 お手数かけます。 よろしくお願いいたします。

    • ベストアンサー
    • Perl
  • 文字コードの変換(Shift-JISからUTF8)

    文字コードがShift-JISのCSVファイルを読み込み、UTF-8のテキストファイルに出力するのに プログラムの中で変更しようとしているのですが、うまくいきません。出力ファイルの文字コードを 確認するとShift-JISのままです。 どなたか教えていただけないでしょうか? ActivePerl v5.16.0を使用し、Encodeモジュールのfrom_toを使用しています。 #!/usr/bin/perl use strict; use warnings; use utf8; use Encode; my $input_file="input.csv"; my $output_file="output.txt"; open (IN, $input_file) or die "$!"; open (OUT, ">$output_file") or die "$!"; while (<IN>){ chomp ($_); my @data=split(/,/,$_); for(my $i=0;$i<@data;$i++){ $data[$i]=Encode::from_to($data[$i],'shiftjis','utf8'); #Shift-JISからUTF-8に変換 $data[$i]=~s/\s+//g; print OUT $_; } print OUT "\n"; } close (IN); close (OUT);

    • ベストアンサー
    • Perl
  • 配列のデータから改行だけを取り除いて上書きしたい

    いつもお世話になっています。 CGIで現在下記のようなファイルがあります。 【sample.cgi】 1<>2<>3<>4<>5<> 6<>7<> これを下記のスクリプトで呼び出し配列に入れます。open(IN,"./sample.cgi"); @DATA = <IN>; close(IN); @data = split(/<>/,$DATA[0]); @N_DATA=(); unshift(@N_DATA,"$data[1]<>$data[2]<>$data[3]<>$data[4]<>$data[5]<>$data[6]<>$data[7]<>"); open(OUT,">./sample.cgi") or &error('書き込み失敗'); print OUT @N_DATA; close(OUT); しかし実行結果は改行が残ったままで、どうにか 1<>2<>3<>4<>5<>6<>7<> という形で出力したいのですがどのように変更を行えば宜しいでしょうか。 恐らく「unshift」の部分が行を追加していっていると思うのですが、printなどで出力するとsample.cgiの中身が空になってしまい・・・。 「読み込むデータに改行があった場合は改行を削除して読み込む」という動作をさせたいのですが・・・。 何卒よろしくお願い致します。

    • ベストアンサー
    • CGI
  • perlで容量の大きいCSVファイルを開く方法

    perlで容量の大きいCSVファイルを開く方法 ファイル容量の大きいcsvファイルから、必要な項目を抜き出して別ファイルにするプログラムを作成したいと思ってます。 csvファイルが少ない場合は動作したのですが、容量が140MBを超えたデータを読み込もうとすると、ブラウザー表示で何も変化いたしません プログラムは以下のようになってます。 ------------------------------------------------- 略 open(IN,"$inport") || &error(" $inport を読み込みopen出来ません"); flock(IN,1); @lines = <IN>; foreach $lines (@lines) { local(@val) = split("\,", $lines); print "$val[0]"; $dat .= "$val[1]\,$val[5]\n"; } open(OUT,">$dcsv"); flock(OUT,2); print OUT "$dat"; close OUT; 略 ------------------------------------------------- 件数も多いので、foreachを$lines (@lines) としないで($start .. $end)として読み込みの件数を制限して対応しようと考えてましたが、うまくいきませんでした。 ご指導いただけますと幸いです。

    • ベストアンサー
    • Perl
  • ファイルの読み込みと出力

    ファイルの読み込みと出力 Perl初心者です。よろしくお願いします。 file.csvのようなファイルを読み込んで、 out.csvのように出力するプログラムを作成しているのですが 途中で変な改行が度々入っているためどうしてもうまくいきません。 (file.csvですが、実際は1500行以上あります。 また、最後に必ずendが入っています。 下記のcsvですがテキスト形式で表示した内容です。) 初歩的な質問で申し訳ありません。 調べる限り調べたのですが分かりませんでした。 どうかよろしくお願いします。 「file.csv」 "2010/1/1","C","こんにちは","田中","end", "2009/10/2","B","おはよう","斉藤","end", "2007/3/20","E","Good mor ning","佐藤","end", "1988/8/16","F","こんばんは","中 村","end", "1999/1/10","A","Hello","木村","end", "2005/9/17","D","おはようご ざいます","斎藤","end", 「out.csv」(このように出力したいです) C,こんにちは,田中,2010/1/1,end, B,おはよう,斉藤,2009/10/2,end, E,Good morning,佐藤,2007/3/20,end, F,こんばんは,中村,1988/8/16,end, A,Hello,木村,1999/1/10,end, D,おはようございます,斎藤,2005/9/17,end, 「今書いているプログラムです」 #!/usr/local/bin/perl use strict; use Fatal qw/ open /; my $csv_file = "file.csv"; my @csv = &readCsvFile($csv_file); open(OUT,">out.csv"); for(my $i=0; $i<=5; $i++){    print OUT $csv[$i][1],",";    print OUT $csv[$i][2],",";    print OUT $csv[$i][3],",";    print OUT $csv[$i][0],",";    print OUT $csv[$i][4],","; } close(OUT); sub readCsvFile {    open(DATA, $_[0]);    while(<DATA>) {      chomp;      push @csv, [ split(/",\"/) ];    }    close(DATA);    return @csv; }

    • ベストアンサー
    • Perl
  • ディレクトリ内CSVデータをすべてまとめる

    スクリプトの存在するディレクトリ /home/XXXX/XXXX/log.pl(完全に固定のディレクトリ) csvファイルの存在するディレクトリ /home/XXXX/XXXX/XXXX/****/YYMMDD.csv(Xは固定*は不定) crontabでCSVファイルを /home/XXXX/XXXX/XXXX/****/ 内のcsvをすべて読み込み時間が古いものを下に 新しい物を上にして /home/XXXX/XXXX/XXXX/****/fix.csv として新たなファイルを生成する。 既に読んだことのあるYYMMDD.csvファイルは再度 fix.csvに書き込まない 次のディレクトリがあるならばディレクトリ内のファイルを読み込み同様の動作をする 以前教えていただいたスクリプトを元にここまでできました。 logファイルに書き込まれている名前のファイルは読み込まないようにしたいのですが どのようにすればいいのでしょうか ▽▽以下スクリプト chdir'/home/XXXX/XXXX/XXXX/'; @files1=reverse(@files1); chomp(@files1); $file1=shift(@files1); until(("" eq $file1)){ @parts1=split(/\//, $file1); open(READLOG,"./$parts1[1]/log"); close(READLOG); open(READFILE,"<./$parts1[1]/$parts1[2]")||die "1$!"; @f1=<READFILE>; close(READFILE); @f=sort(@f1); open(WRITEFILE,">>./$parts1[1]/fix.csv")||die "3$!"; foreach $str (@f){ print WRITEFILE "$str"; } close(WRITEFILE); $file1=shift(@files1); #次のファイル名の取り出し open(BKFILE,">>./$parts1[1]/log")||die "3$!"; print BKFILE $parts1[2]."\n"; close(BKEFILE); } △△以上

    • ベストアンサー
    • Perl
  • ファイルの書き込み2

    またまた失礼します。 やりたいことは以下です。 1.ディレクトリを開く。 2.ファイル達を読み込み。 3.追記用のデータファイルを開く。 4.「2」にデータを追記 5.別のディレクトリに書き出し。 以上です。 4番がうまくいきません。 ためしに4の工程を抜かすと問題なく書き出されます。 4の工程でやりたいことは、 1.タブ区切りのテキストファイルを読み込み。 2.書き出し用に読み込んだ(追記したいファイル)<productのpath="[ココの値!]"を取得。 3.「2」番で取得した値と「1」番で取得した値を比較。 4.「3」がtrueの行を追記して書き出し。 以上。 要するになにがしたいかというと、 仮にタブ区切りテキストには10行分のデータがあるとします。 それぞれの行には3つ分の値が入っており、先頭にIDが付いています。 一番最初に読み込んだファイル(追記したいファイル)にも同様にIDが振られており(<product path="ココ")そのIDとタブ区切りテキストのIDが一致した行だけ追記したいということです。 下記のコードだとなぜか、 10行分のデータがすべて追記されてしまいます。 コードは以下です。 #!/usr/bin/perl #既存ファイル読み込み&追記 $n_dir = "newXml/"; $b_dir = "xml/"; opendir(DIR, $b_dir); while($file = readdir(DIR)){ $bfile="$b_dir$file"; $nfile="$n_dir$file"; $dfile="data/data.txt"; if (-T $bfile) { open(IN, $bfile);#既存ファイルオープン @list = <IN>; close(IN); open(OUT,">$nfile");#書き出しファイルオープン foreach $line (@list) { if ($line =~ /\<product/){ $line =~ /path=\".*\"/;#path取得 $1; } if ($line =~ /\<\/product\>/) { open(IN, $dfile);#追加データファイルオープン while($data = <IN>){ chomp(@data = split(/\t/,$data)); $data[0] =~ s/\//_/g; if($data[0] == $1){#取得したパスとdata.txtとってきた値を比較 print OUT <<EOF; <ds path="$data[0]">$data[1]</ds> <kw>$data[2]</kw> $line EOF } else{next;} } close(IN) }else{print OUT $line;} } close(OUT); } else{next;} } closedir(DIR); 長々と申し訳ありません。 エラーなどは特にありません。 ご協力お願いします。

    • ベストアンサー
    • Perl

専門家に質問してみよう