PerlでのCSV書き込みについての質問

このQ&Aのポイント
  • Perl初心者の方が、投票プログラムのCSV書き込みについて質問されています。投票された際のカウントアップとファイルへの書き込みが正しく行われず、どこが間違っているのかが分からないとのことです。
  • 質問内容は、Perlで投票のプログラムを作成しているが、投票してもカウンタが0のままになってしまうというものです。具体的には、投票された際に対応する番号のカウントを増やし、その結果をCSVファイルに書き込むという単純な処理がうまくいっていないようです。
  • 質問者はプログラムが間違っていると考えており、どこが問題なのかわからないため、助言を求めています。提供されたプログラムは実際に使われているものであり、データを読み込み、カウントアップした後にファイルに書き込む処理が含まれています。
回答を見る
  • ベストアンサー

PerlでのCSV書き込みについて質問です。

perl初心者です。 perlで投票のプログラミングを作ってるのですが、 どうもうまく動きません。 やりたいことは ・投票されたら  1)csvを読み込む  2)該当するNOのカウントをアップ  3)csvに書き込む という単純なことなのですが、 投票してもカウンタは0のままになってしまいます。 書き込み部分のプログラムが間違っているとは思うのですが 何が間違っているのかがどうしてもわかりません。 どなたかお知恵を貸してくださいm(__)m プログラムは下記のようになっています。 ================= foreach my $key (@key) { $val = $in{$key}; $in{$key} = &Jcode::convert(\$val, 'sjis'); } # データオープン open(DAT,"+< $datfile"); flock(DAT, 2); my @data; while (<DAT>) { push(@data,$_); if (eof) { last; } } # データ書き込み truncate(DAT, 0); seek(DAT, 0, 0); my $i=1 while (i<11){ my ($no,$name,$count) = split(/,/, $data[$i]); if($val eq $no){$count++;} if (eof) { last; } $i++; print DAT "$no,$name,$count,\n"; } close(DAT); ================= どうぞよろしくお願いします。

  • cyogi
  • お礼率100% (1/1)
  • Perl
  • 回答数1
  • ありがとう数1

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

  • ベストアンサー
  • ralf124c
  • ベストアンサー率52% (232/446)
回答No.1

ソースがK&RスタイルなのでC経験者と見ました(書き方もCですね)。 参考意見だけで十分かと思いますので・・・。 *********************************************** if (eof) { last; } は流れの中をみてると全部不要かも・・・ *********************************************** my @data; while (<DAT>) { push(@data,$_); if (eof) { last; } } -----------------------------------------------は以下のように書いた方がすっきり my @data = <DAT>; *********************************************** my $i=1 while (i<11){ my ($no,$name,$count) = split(/,/, $data[$i]); if($val eq $no){$count++;} if (eof) { last; } $i++; print DAT "$no,$name,$count,\n"; } -----------------------------------------------CプログラマはWhileがお好き→条件指定を少しでもミスるとエンドレス foreach(@data){  my ($no,$name,$count) = split(/,/);  if($val eq $no){$count++;}  print DAT "$no,$name,$count,\n"; } *********************************************** truncate(DAT, 0); seek(DAT, 0, 0); -----------------------------------------------消してから戻すのではなく戻してから消す方が理にかなってると思う seek(DAT, 0, 0); truncate(DAT, 0); *********************************************** あとopenやflock,seek,truncateなどは「or die "xxxxx"」でエラー処理したほうが無難 *********************************************** 「flock」はOSや環境に左右されるので信用しないの が吉。 CGIのアクセスカウンタのプログラムを参考 にしたほうが良い。 *********************************************** できれば、カウントするファイルを1カウンタ1フ ァイルとし、危険分散させたほうがリスクが低くなる と思います。 ***********************************************

cyogi
質問者

お礼

ralf124cさん 細かく説明していただいて、本当にありがとうございます! Cは、学生の頃習った記憶が・・(○十年前・・)。 プログラムというものから離れてて、久しぶりにさわったのですが、 perlの配列をまったくわかっていませんでした。 アドバイスいただいた分と配列をやり直しと、いろいろさわって、やっと解決できました! ありがとうございました!! また何かあったときにはどうぞよろしくお願いいたしますm(__)m

関連するQ&A

  • 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
  • 行数が30万件ほどあるCSVから、PHP経由でMysqlにデータを投入

    行数が30万件ほどあるCSVから、PHP経由でMysqlにデータを投入しようとしています。 2000件ごとにファイルを分割し、再度各ファイルを読み込みなおして、insertしようと考えました。 ところが、ファイル分割で2000件ごとに区切った場合、最後の2000件に満たない端数分をファイルに落とす方法がわかりません。 どなたか教えていただけないでしょうか。 ※かなり冗長な書き方をしているかと思いますので、改善点等あればご指摘いただければ幸いです。 以下サンプルコード------------------------------------------------------ $count = "0"; $max = "2000"; //ファイルあたりの行数 $file_count = "0"; //ファイル名につける連番 $RF = fopen( "base_file.csv", "r") or die("ファイルが開けません"); while (($data = fgetcsv($RF)) !== false) { if($count < $max){ //順番を入れ替えたり、データをいじるかもしれないのでsprintf $lines.= sprintf("%s,%s,%s,%s,%s,%s,%s\n", $data[0], $data[1], $data[2], str_replace(" "," ",$data[3]), //全角スペースを半角に変換 $data[4], $data[5], $data[6] ); } if($count == $max){ //ファイル名生成 $fileno = zerofill($file_count); $filename = "./files/datafile_".$fileno.".dat"; $WF = fopen($filename, "w"); fputs($WF, $lines); fclose($WF); //書き込みデータを空にする $lines = ""; $file_count++; $count = "0"; } $count++; } fclose($RF); //ファイル名の連番を0で埋める function zerofill($val){ if($val < 100){ if($val < 10){ $ret = "0".$val; } $ret = "00".$val; } return $ret; }

    • ベストアンサー
    • PHP
  • Perl ページ表示遅い ループの改善

    ソースが汚いかもしれませんが、ご教示お願い致します。 実行したいことは、できてはいるのですが、 「表示が遅い」です。 ループのやり探し、 サーバー上でのHTML生成が 原因だと思うのですが、 どう改善すればいいのかわかりません・・・ ・下記のソースの簡単な説明 あるテキストファイルにCSV方式でデータを記録してあります。 (最終で200万バイトくらい) (現在 12万バイト) そのデータで1列目に順位の数字があり (~20位前後) それを、いろんな条件で絞込し一気に表示してます。 そこから、サーバー上でテーブルとして表示させているのですが とにかく遅いです。 ・・・サーバー上で計算するからでしょうが・・・ もう少し速くする方法はないでしょうか? スクリプトでHTMLを生成させることはできるのですが、 サーバーにデータのみを保存させ そこから生成させたいのです・・・ ※だいたい10秒前後(Wi-Fi有りで) Wi-Fiの環境がなく、さらに回線が3Gまでに なっている人だと絶望的な状況だと・・・ 下記のソースで、 (1)おかしな点 (2)改善すれば速くなる点 (3)別の案 を教えてほしいです・・・ ------ソース------ my @DataNo = ("13","14","2","1","8"); my $DataName; for(my $dn=0;$dn<=$#DataNo;$dn++){  my $DataNo = $DataNo[$dn];  my ($No) = split(/,/, $DataNo);    if($No eq "13"){ $DataName = "A" }  if($No eq "14"){ $DataName = "B" }  if($No eq "2"){ $DataName = "C" }  if($No eq "1"){ $DataName = D" }  if($No eq "8"){ $DataName = "E" } print <<END;  <h2 class="ResMidashi"> $DataNameデータ</h2>   <table class="ResultData">    <tr>     <td>[$DataName]</td>     <th>Test1</th>     <th>Test2</th>     <th>Test3</th>    </tr> END my %hash = (); my @arrey; open(F, "<","../Test/Test.txt") or die("error :$!"); eval{ flock(F, 1) }; while(<F>){  chomp;  my @temp1 = split /,/;  push @arrey , $temp1[$No]; } close F; foreach (@arrey) {  $hash{$_}++; } my @Data; if($No eq "1" || $No eq "2" || $No eq "9"){  @Data = sort keys %hash; } else{  @Data = reverse sort keys %hash; } my $matches = 0; my $Count1 = 0; my $Count2 = 0; my $Count3 = 0; for(my $Co=0;$Co<=$#Data;$Co++){  my $DATA = $Data[$Co];  my ($Main) = split(/,/, $DATA);  open(F, "<","../Test/Test.txt") or die("error :$!");  eval{ flock(F, 1) };  while(<F>){   chomp;   my @temp2 = split /,/;   if( $temp2[5] eq "$JoukenA" and $temp2[6] eq "$JoukenB" and $temp2[7] eq "$JoukenC"){    if( $temp2[$No] =~ /^$Main$/ ){     $matches++;     $Count1++ if $temp2[0] == "1";     $Count2++ if $temp2[0] == "2";     $Count3++ if $temp2[0] == "3";    }   }  }  my $T;my $P;  if($matches){   $T = ($Count1 / $matches) * 100;   $T = sprintf('%.2f', $T);   $P = (($Count1 + $Count2 + $Count3) / $matches) * 100;   $P = sprintf('%.2f', $P);   my $Frame1;my $Frame2;   if($Puk ne "0.00"){ print <<END;    <tr>     <td>$Main</td>     <th>$Count1-$Count2-$Count3-$matches</th>     <th>$T</th>     <th>$P</th>    </tr> END   }  }  $matches = 0;  $Count1 = 0;  $Count2 = 0;  $Count3 = 0;  if($Co eq $#Data){last;} } print <<END;   </table> END }

    • ベストアンサー
    • Perl
  • PerlからのCSV出力

    Perl初心者です。 PerlでOracleに接続し、結果をCSVを出力したいのですが 下記プログラムだとなにも出力されません。 Oracle10g OS:Linux *** #!/user/bin/perl # # # DBI モジュールの読み込み use DBI; #接続 my $hDb = DBI->connect("dbi:Oracle:dbname", "user/pass") or die "CONNECT ERROR $DBI::errstr"; #SELECT # $hSt = $hDb->prepare("SELECT ID,NAME FROM MASTER"); open(OUT, ">data.dat"); #実行 $nRes = $hSt->execute; #データの取得 while($raRes = $hSt->fetchrow_arrayref) { print OUT join(",", @$raRes), "\n"; } # ファイルクローズ close(OUT); $hSt->finish; $hDb->disconnect;

  • CSVの操作方法について

    CSVの操作方法について 以下のようなソースでcsvからデータを配列に格納しています。 わからない事が2点あるのですがどのようにすれば可能でしょうか? ※csvの例 No,name,age 1,あああ,25 2,いいい,28 3,ううう,33 1:csvのカラム名を「No」とした場合ここに数字を入れます。IDみたいなもんです。 この数字の番号だけの情報を取得するにはどうすればいいでしょうか? 2:上記同様に「No」の1~5までといったような指定した番号の情報だけを取得するには どうすればいいでしょうか? // 読み込み開始行 $start = 1; // 初期化 $row = array(); // 読込み行数 $h = 0; $filename = APP_DIR . '/csv/' . $filename; $handle = fopen($filename, 'r'); while (($data = self::fgetcsv_reg($handle)) !== false) { $_enc_to = mb_internal_encoding(); $_enc_from = 'sjis'; mb_convert_variables($_enc_to, $_enc_from, $data); if ($h >= $start) { for ($i = 0; $i < count($data); $i++) { $row[$h - 1][$i] = $data[$i]; } } $h++; } fclose($handle);

    • ベストアンサー
    • PHP
  • PHPでCSVファイルの任意の行だけを編集したい

    簡易掲示板の管理画面を作成しようと思っていますが、 うまくいかずに悩んでいます。 入力フォームで送られてきた内容をcsvファイルに書き込み、 それを表示するという掲示板なのですが、 管理画面ではそのcsvファイルを操作して、 任意の書き込みを修正・削除できるようにしたいと考えています。 以下、PHPコードです。 if($mode == "edit"){ foreach($csv as $val){ list($li_no, $li_date, $li_comment) = split("\t",$val); if($li_no == $info_no){ $csv[$info_no] = "$id\t$date_y/$date_m/$date_d\t$comment\t\n"; fputs($fp,$csv[$info_no]); fclose($fp); } } }else{ $dat = "$id\t$date_y/$date_m/$date_d\t$comment\t\n"; $fp = fopen('$csv' , 'w'); fputs ($fp, $dat); for ($i=0; $i<1000;$i++){ fputs ( $fp,$csv[$i]); } fclose($fp); } 編集用のフォームで$info_noを飛ばして、 CSVファイル内の$li_noと一致した場合、 $li_noの行を書き換えという処理をしているつもりなのですが、 なぜか、他の行がすべて消えて、 編集した行だけがファイル内に残ります。 いろいろと検索して試してはみたのですが、 どうもうまくいきません。 どなたか教えてください。 お願いします。 これ以外の方法で簡単にできる方法があれば そちらも教えていただけたら幸いです。

    • ベストアンサー
    • PHP
  • perlの構文間違いについて

    以下のような、perlの構文で$infoをmyスコープで宣言しつつ、$datという変数が真なら$infoに$datが入ることを期待しているのですが、まちがっているのでしょうか? my $info = $dat if ($dat); よろしくお願いします。

    • ベストアンサー
    • Perl
  • CSVで指定した行から出力をする方法

    CSVから、30件データを取得するために最下部のようなコードを書きました。 しかし、「次のページ」等でもう30件(つまり31行目から)データを出力させたい場合は、どこをどのように修正すればいいのでしょうか。 $fp = fopen("exmple.csv", "r"); $repeat = 30; $count = 1; while ($data = fgetcsv($fp, 10000)) { if ($count > $repeat) { break; } print($data[0]. $data[1]. $data[2]); $count++; } ご回答お願いします。

    • ベストアンサー
    • PHP
  • 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の初心者です。はじめまして。 質問タイトルそのままなのですが、データからある文字列の次の行を出力するにはどのような記述をすればよろしいでしょうか?よろしくお願いします。 ・データは1ファイルで2000あります。1つのデータは[X,Y]で始まり、次の[X,Y]の前までになります。 ・出力はCSVファイル。 ・DAT errがあった場合はその次の行を出力。なかったら、DAT列は空白にする。 #!/bin/perl open(FILE,"<$ARGV[0]"); open(OUT,">$ARGV[0].csv"); ########################## err count ########################### print OUT "X,Y,NUMBER,DAT,\n"; while(<LOG>){ if($_ =~ /X=(.+)\,Y=(.+)/){ chomp($_); print OUT "\n$1,$2,"; } if($_ =~ /NUMBER (.+)/){ print OUT "$1,"; } if($_ =~ /DAT err/){ print OUT "PASS,0,"; } } close(OUT);

    • ベストアンサー
    • Perl

専門家に質問してみよう