集計データの取得方法とCSVファイルの値の取り出しについて

このQ&Aのポイント
  • アンケートスクリプトでフォームからPOSTされたデータを受けて、CSVファイル操作を行い、集計データを取得する方法について教えてください。
  • CSVファイルの形式などについて指定はありませんが、1年を4分割してデータを取得する方法について教えてください。
  • CSVファイルから特定範囲のデータを取得したい場合、localtimeを使用して日付を比較し、範囲を絞ってデータを取得する方法について教えてください。
回答を見る
  • ベストアンサー

集計データ

いつもお世話になってます。 アンケートスクリプトで、フォームからPOSTされたデータをCGIで受けて、サブルーチン(CSVファイル操作) で回して該当のデータをフォームに返してます。 設問ファイル(html)→メインルーチン(cgi)→サブルーチン(pl) そこで、数十通りある設問のカテゴリ別に集計データを取りたいと思ってます。 <内容> 1列目…カテゴリ 2列目…別全データ件数 3列目…該当データ件数 <データ> 1,2000,258 2,2000,320 3,2000,115 ・ ・ ・ &ReadParseで、$in{'name1_1'},$in{'name1_2'},$in{'name1_3'},$in{'name2_1'},…のように 受けていますが、このkeyごと(name1_~)にCSVファイルへ書き出したいです。 それから別件で、CSVファイルの値の取り出しについてお聞きしたいのですが、 <内容> 1行目…初期区分 2行目…月日の範囲(1年を4分割) 3行目…結果区分 <データ> 1,1,1,1,2,2,2,2,3,3,3,3 "0405,0612","0613,0920","0921,1215","1216,0404", "0409,0718","0719,1020","1021,0107","0108,0408", "0321,0620","0621,0828","0829,0115","0116,0320" 1,2,3,4,1,2,3,4,1,2,3,4 ※2列目のデータは長くなってしまう為、3行に分けています。規則性はありません。 やりたいことは、まず1行目の区分を割り当てて、localtimeで当日の日付から2行目の範囲を絞って 3行目の結果区分を得たいのですが、どうやればよいのか教えて下さい。 現在は、CSVの形式がきちんと決まっていないので、","のように範囲を指定していますが、 CSVの形はこれ以外でも構わないので、どうか知恵を貸して下さい。 宜しくお願い致します。

  • Perl
  • 回答数3
  • ありがとう数2

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

  • ベストアンサー
  • hrm_mmm
  • ベストアンサー率63% (292/459)
回答No.3

あ、失礼しました、実行チェックせずに投稿したら、微妙にいろいろ不具合が。。 不具合1 >@data2 = split( ',', $line2 ); ""の中にもカンマがあるので、カンマのみで分割すると、開始日と終了日も泣き別れになってしまう →先頭と最後の"を除いておいて、 「","」 で分割 $line2 = substr($line2, 1,-1); ###引数3つめ負数で末尾から削除 @data2 = split( '","', $line2 ); 不具合2 perlでは、ループから抜け出す時は、lastを使うのでした。 breakは、java,javascript,Cなどでの用語 →forループ内の break;を last;に置き換えて下さい 回答1 >>my $hantei=-1; >は、なぜマイナス1を入れているのでしょう?? 配列の添え字を$hanteiに入れるようにしていますが、 配列の添え字は0開始で最大値はいろいろ変動があるけど、どこかで判定に引っかかれば-1が入ることはあり得ないためです。 ループ終了後に-1であれば、最初の開始日よりも前である=最後の期間に入れる、としています。 回答2 >>for( $i=scalar(@data2)-1; $i>=0; $i-- ) >これは、要素数をforループの意味合いでいいですか? scalar(@data2)-1配列添え字の最大値から0へまでの減少ループです。 そういえば、 scalar(@data2)-1 → $#data2 っていう表現があったんでした。 ### forループ内のみ再掲 for( $i=$#data2; $i>=0; $i-- ){ $start = substr($data2[$i], 0,4); if( ($start cmp $dt) <=0 ){ # 開始日と同じかそれよりも後の日付の時 $hantei=$i; last; } } if( $hantei== -1){ $hantei= $#data2; }

polalis
質問者

補足

hrm_mmm様、 ご回答及びご丁寧な解説、とても助かります。 また、ご質問させてください。 戻り値の数値が例えば、「2」だとしたら「0612」 "0405,0612","0613,0920"→ 1 =「0405」,2 =「0612」,3 =「0613」,4 =「0920」 こんな感じになるのでしょうか? 最初に掲載した、下記のデータでやっているのですが 1行目も引数を与えて、絞り込むようなことはできますか? 1,1,1,1,2,2,2,2,3,3,3,3 "0405,0612","0613,0920","0921,1215","1216,0404","0409,0718","0719,1020","1021,0107","0108,0408","0321,0620","0621,0828","0829,0115","0116,0320" 1,2,3,4,1,2,3,4,1,2,3,4 度々、申し訳ありませんが宜しくお願いします。

その他の回答 (2)

  • hrm_mmm
  • ベストアンサー率63% (292/459)
回答No.2

>データ部は、"4月5日~6月12日","6月13日~9月20日","9月21日~12月15日","12月16日~4月5日"という意味 日付範囲に重なりは無いのですよね? 年越しするのは最後のデータのみなら、開始日だけを文字列の大小比較すればいけるのでは? ### $line2 に2行目を読み込んだとして @data2 = split( ',', $line2 ); my ($i,$start); my $hantei=-1; for( $i=scalar(@data2)-1; $i>=0; $i-- ){ $start = substr($data2[$i], 1,4); if( ($start cmp $dt) <=0 ){ # 開始日と同じかそれよりも後の日付の時 $hantei=$i; break; } } if( $hantei== -1){ $hantei= scalar(@data2)-1; } ### $hanteiに何番目の日付範囲に一致したかが入っている。

polalis
質問者

お礼

hrm_mmm様の提示されたコードを基に、なんとか 自己解決することが出来ました!! ありがとうございます。とても感謝です。

polalis
質問者

補足

hrm_mmm様、ご回答ありがとうございます。 >日付範囲に重なりは無いのですよね? はい、ありません。 開始日のみを大小比較…そういった発想が浮かびませんでした。 確かにそうですよね!今後の参考になります。 ところで、当方Perl初心者の為、解説して頂きたいのですが >my $hantei=-1; は、なぜマイナス1を入れているのでしょう?? それから >for( $i=scalar(@data2)-1; $i>=0; $i-- ) これは、要素数をforループの意味合いでいいですか? $line2 = '"0405,0530","0531,0904","0905,1025","1026,0404"'; として、実行したのですが「0」が返ってきてしまいます。 度々、申し訳ありませんが、ご教授下さい。

  • hrm_mmm
  • ベストアンサー率63% (292/459)
回答No.1

どこらあたりまで出来ているのか、ソースも提示していただかないと、ただの丸投げなので、あまり回答がつかないのでは? >このkeyごと(name1_~)にCSVファイルへ書き出したいです。 #FH にCSVファイルへ書き込み用 file handle設定して foreach (keys %in){ print FH $_ .','. $in{$_} . "\n"; # 一行ずつ出力 } close FH; >CSVファイルの値の取り出し >※2列目のデータは長くなってしまう為、3行に分けています。規則性はありません。 常に3行であることが確実ならば、ファイルの2-4行目は、読み込んだら終端の改行コードを削除(chomp)して連結してしまえば、 後は、split(',' , $line ) で、それぞれの列ごとに配列に格納出来ます。 何行繋げるかに規則がないとちょっと困るかも。 日付時刻別の振り分けは、どういう規則で、ファイルに書いてあって、どういう規則で取り出したいのかを詳細に記述してみて、まずは、ご自分で組んでみて下さい。

polalis
質問者

補足

hrm_mmm様、アドバイスありがとうございます。 確かに、丸投げ状態ですね…私自身、Perlをよく解っていないため、質問の要所をとらえて ないのかもしれません。 >#FH にCSVファイルへ書き込み用 file handle設定して こういう書き方で、ハッシュの値がファイルに取り出せるのですね! 大変、参考になりました。 >常に3行であることが確実ならば、ファイルの2-4行目は… これは、この投稿の見栄えをよくするために3行に分けたということで、本来は 1行になっている部分です。 ですから、実際のデータ行は3行になっています。 "0405,0612","0613,0920","0921,1215","1216,0404", というデータ部は、 "4月5日~6月12日", "6月13日~9月20日", "9月21日~12月15日", "12月16日~4月5日" という意味で、 本日日付を取得して ($ss, $mn, $hh, $dd, $mm, $yy, $yb) = localtime(time); $yy += 1900; $mm++; $str = (%02d%02d); $dt = sprintf($str,$mm, $dd); にて$dtは、データどの部分にマッチするのか? という結果を得たいのです。 配列への格納等は、出来るのですがこういったCSVデータを、日付の範囲に変えてマッチさせる やり方があれば教えて頂きたいと思っています。

関連するQ&A

  • 該当するデータを集計したい

    集計についての質問です。 よろしくお願い致します。 A1:N?(最終行は定まっておりません。ファイルによってまちまちです)の表があります。 A列に入力されている文字が11文字(半角のアルファベット1文字+数字10桁)、且つB列が空白のとき、 その同じ行のC列:N列の情報を1つのシートに集計をしたい。 【環境】 同じフォルダ内にエクセルファイルがいくつかあります 保存されているエクセルファイルは全て集計の対象になります 表の形式は全て同じになります シートは全て1枚で同じシート名になります 集計シートの2行目より該当するデータをあるだけ追加していくようなイメージになります。 要は同じフォルダ内の複数のエクセルファイルで、該当するデータを、 新たに1つのシートでまとめたいと考えております。 該当データが不特定なので追記していく方法がよくわかりません。 どなたかご教授いただけますでしょうか

  • cvsファイルの中身を簡単に検索したい

    失礼します。 あるフォルダに沢山のcsvファイルが入っているとします。 それらのcsvファイルの中身で、行に'test'という文字列が入っている csvのファイル名と、ファイル毎の'test'の該当件数を知りたい場合、 何か良い方法はありませんでしょうか?

  • フォームに入力された値から、PHPでCSVデータを読んで表示させたい。

    フォームに入力された値から、PHPでCSVデータを読んで表示させたい。 現在、PHPでお申し込みフォームを作成中なのですが、どこのページから来たかを判別するための値から、そこのページ名を表示させたいのですが、うまくできません。 CSVファイルには1列目に値、2列目にページ名が書かれたものが、50行あります。その中から、 例えば値が5だったら、5行目の2列目に書かれているページ名を表示させたいのですが、どうしたらいいのか、教えていただきたいです。

    • ベストアンサー
    • PHP
  • フォームデータのcsv保存について

    お世話になります。フォームに入力されたデータを csvファイルに保存するというcgiの作成をしています。 初めてcgiを作成するので、書籍の真似をして作成した のですが、おかしいデータが保存されてしまいます。 質問の項目数は5個で以下のとおりです <FORM ACTION="./ans1.cgi" METHOD="POST"> 名前:<br> <input type="text" name="name" size=30> <br> 1:<br> <input type="text" name="a1" size=30> <br> 2:<br> <input type="text" name="a2" size=30> <br> 3:<br> <input type="text" name="a3" size=30> <br> 4:<br> <input type="text" name="a4" size=30> <br> <INPUT type="submit" value="送 信"> <INPUT type="reset" value="リセット"> <BR> </FORM> cgiの中身です。 #! /usr/bin/perl require './cgi-lib.pl'; $answer = 5; $ansfile = "kotae.csv"; &ReadParse(*in); $name = $in{'name'}; for($n = 1; $n <= $answer; $n++ ) { $a[$n] = $in{"a$n"}; } open (FILE,">>$ansfile"); flock (FILE,2); print (FILE "\"", $name); for($i = 1; $i <= $answer; $i++ ) { $a[$i] = ~ s/\"/""/g; print FILE "\"\,\""; print FILE $a[$i]; } print FILE "\"\n"; flock(FILE,8); close(FILE); print "Content-type: text/plain\n\n"; print "<HTML><BODY>\n"; print "tesuto"; print "</body></HTML>"; exit; csvファイルの中身を見ると、最初の列には、項目1で 記入したデータが入ってますが、項目2以降 は4294967295と数字が入ってます。どうも1個目の回答 欄のデータはちゃんと取得されてるのですがそれ以降の が取得されていないみたいです。 よろしくお願いいたします。

    • ベストアンサー
    • CGI
  • Accessで、複数のテーブルからデータを繋げたい

    ■テーブル1 2011年データ 行:名前 列:年月日 201101~201112 行:商品名 値:件数 ■テーブル2 2010年データ 行:名前 列:年月日 201001~201012 行:商品名 値:件数 となっております。 列を伸ばして、201001~201112までのデータにしたいのですが クエリの組み方が不明です。 ネットでサーチはしたのですが、該当のものが出てこず、良ければ教えて下さい!

  • 定形のCSVファイル(多数)のデータを1つのファイルにまとめたい。

    定形のCSVファイル(多数)のデータを1つのファイルにまとめたい。 列の項目は定形で、100~200行のデータが書かれたCSVファイルが多数あります。 今はNO.1のファイルのデータの続きに、NO.2でコピーしたものを貼り付け、又、NO.3でコピーしたものを貼り付け、いわゆるコピーアンドペーストでやっています。 でも、コピー範囲を間違えないように進めるとなると、時間がかかります。 もっとかんたんな方法があったら教えてください。 よろしくお願いします。

  • VBA でCSV集計

    VBAをはじめて1ヶ月のものです。 VBAの集計ツールを作成していますが 思うようにいかず、お知恵をお借りしたいと考えています。     abcというフォルダ配下に以下のように4桁の日付を示す フォルダが日付毎にあります。(いくつあるかはわかりません。) さらにその配下にいくつかのcsvファイルがおいてありますが aaa.csvというcsvのみ抽出し 最終的には合体.csvのような集計CSVを作成したいと考えています。 以上よろしくお願いいたします。 (1) abc → 0812フォルダ <aaa.csv>     A列     B列    C列 1行 100     200    8月12日                       2行 100     100 3行 200     200 4行 300     100 5行 100     100 6行 200     200 7行 400     100 8行 100     100 (2)abc → 0813フォルダ <aaa.csv>      A列     B列     C列 1行   0      300    8月13日              2行 100      100 3行 100      200 4行 100      200 5行 100      200 6行 300      200 7行 300      400 8行 200      100 ↓ (3)<合体.csv>     A列     B列      C列     D列     E列     F列     G列    (日付)  (A1~A4計)(A5~A8計)(合体B+C)(B1~B4計)(B5~B8計)(合体E+F) 1行 8月12日   700      800     1500     600     500     1100 2行 8月13日   300      900     1200     800     900     1700

  • CSVファイルの行と列のセルってどうやって指定するのですか?

    たとえば、1行目の2列目のセルの値を消したい。 2行目の5列目のセルの値に数字の5をいれたい。 って場合、行だったら $FILE=data.csv; open(IN, $FILE); @data=<IN>; close(IN); このときの $data[2]は3行目ですよね? では3行目の3列目はどうやって指定するのでしょうか?たとえば3行目の3列目のセルの数字の5だったのをperlを実行したらセルの中を6に書き換えるのはどうしたらいいのでしょうか?

    • ベストアンサー
    • Perl
  • ファイルから読み込んで配列へ

    PerlでCGIスクリプト(掲示板もどき)を作成しています。 配列の操作がうまくいかず、ご教授頂きたいと思います。 <やりたい事> 1.ブラウザ上のフォームからの入力を、カンマ区切りでテキストファイルに追記して保存。 2.そのテキストの一部を使ってHTMLで表を作る。 <実際の作業> 1.フォームからのデータはcgi-lib.plで連想配列として受け取り、unshiftでテキストファイルへ追記する。 &ReadParse; #フォームからデータを受け取る $o=$in{'name'}; $p=$in{'mail'}; $q=$in{'title'}; $r=$in{'comment'}; open(IN,"xxx.txt"); @tmp1=<IN>; close(IN); #1件1行として新規データを追加する unshift (@tmp1,"$oo" , "," , "$pp" , "," , "$qq" , "," , "$rr","\n"); open(OUT,">xxx.txt"); print OUT @tmp1; close(OUT); 2.xxx.txtのデータを読み込んで、1列目(name)と3列目(title)だけを使った表を作る。 データを読み込む時点でつまづき、先に進めません。 <テキストファイルの例> 1行目:a,b,c,d 2行目:e,f,g,h 3行目:i,j,k,l 以下同様 <症状> print @tmp1;とすると、a~lの全てのデータが表示される。 $tmp1[0];とすると、(a)のみ表示される。 $tmp1[1];とすると、カンマ(,)が表示される。 $tmp1[2];とすると、(b)が表示される。 <質問> 一つの行(配列)に対して2回繰り返す処理(nameとtitle)と、行単位で繰り返す処理(1行目、2行目…)を合わせればいいのだろうと思っていますが、どうすればいいのかわかりません。 気分的には↓こんな感じです。 foreach { "行の処理" foreach { "列の処理" } } そもそも、区切り文字であるカンマが、配列に格納されている時点で失敗しているのかな?とも思っています。 宜しくお願いします。 なお、不足している情報がありましたら補足いたします。

    • ベストアンサー
    • Perl
  • データの抽出

    エクセルの使用方法で、質問です。 一つのファイルに入っているデータB  ×××   ○○○   △△ 1------   ------   ---- 2------   ------   ---- 3------   ------   ---- 4------   ------   ---- ・ ・ ・ と、もう一つのファイルに入っているデータA  ×××   ○○○   △△  ■■■ 1------   ------   ---- 2------   ------   ---- 3------   ------   ---- 4------   ------   ---- ・ ・ ・ の△の行のマッチングを行い、重複している列に、データBの該当している列のコピー■の行に 書き出したいのですが、何かいい方法はないでしょうか。 よろしくお願いいたします。