Perl初心者の質問:CSVから値を割り出す方法は?

このQ&Aのポイント
  • Perl初心者がCSVファイルから値を割り出す方法について教えてください。
  • また、CSVファイルの一番右の列を指定すると値が割り出せない現象が起きます。この解消方法も教えてください。
  • さらに、Open関数でdieが発生した場合にログに出力する共通関数の作成方法も教えてください。
回答を見る
  • ベストアンサー

CSVから値の割り出し3

Perl初心者です。 締め切った要件にて、またお聞きするのは回答者様達に 大変失礼だと思ったのですが、どうしても解らなかった為 また教えてください。 「CSVからの値の割り出し2」にて、コードまで送って頂いた のですが、私の動作確認不足のために教えていただいた方に 不快な思いをさせるのは、大変心苦しい限りです。 申し訳ありません。。。 コードの概要は、渡されたパラメータを元にCSVファイルの カラムを絞っていって、評価した値を最後のレコードにて 割出す…というスクリプトです。 ※お手数ですが「CSVからの値の割り出し2」を参照して下さい。 CSVファイルの一番右の縦列をパラメータに指定すると何故だか 値が割出せません。ほかは問題ないのですが。 $data[x]->[y]で確認すると、値は存在するのにマッチして くれません。 これは、どうすれば解消できますか?教えてください。 それと、Open関数にて「die」が選択されたときにlogに出力 するというのをサブルーチンで、共通関数みたいな形にした いのですがどうすればいいのでしょう? よろしくお願い致します。

  • Perl
  • 回答数5
  • ありがとう数1

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

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

#4>実行ログなんかもとりたいのですが、そういった場合の書き込む頻度が高い場合でも必要ないですか? 1つのプログラム(バッチ処理)からなら、要らないと思います。 #4>複数のCSVファイルを一気に読ませたいんです。 要はこれを何度も処理させることを、このスクリプト上で出来ませんでしょうか? 処理の流れがどういう具合なのかよくわからないので、なんとも言えないですが、トップの部分でCSVファイル毎ループしてやればいいような気がします。 #4>↑場合、簡略化して書く方法ってありますか? 例えば、 prog.pl data.csv para1 para2 para3 para4 とかの場合 $filename = shift; func(@ARGV); #para1,para2,para3,para4 が渡される。 でいいと思います。 そういうことでないなら、$para1,$para2,$para3,$para4 のように個別に名前を付け直すより、配列のまま使うのがいいと思います。(配列でコピーするとか)

polalis
質問者

お礼

BLUEPIXY様、 お世話になってます。 長きに渡り、なにからなにまで感謝の気持ちでいっぱいです。 別件でお邪魔することもあると思いますが、そのときはまた 宜しくお願いいたします。 本当にありがとうございました^^

その他の回答 (4)

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

#3>自己解決しました。 それは、良かったですね^^ #3>大丈夫です。 なら別に良いです。 die じゃなくて、単にexit を使って終了すればいいかもしれませんね。 #3>書き込む場合はロック処理をしたほうがいいのはわかるんですが、読み込むときにも設置したほうがいいのですか? CSVデータの話ですよね。 読み込んだデータを変更して書き込む処理をしない場合(つまり、読み出ししかしない場合) 必要ないと思います。 書き込む場合も、バッチ処理で、そのプログラムしか書き込みしないような場合特別必要ないと思います。 #3>メイン処理のOpenとcloseを繰り返して、負荷をかけた状態のパフォーマンスをみたいんですが、どうするのが効率的ですか?? もう一つイメージがわかないんですけど、 UNIXを使っていてshell から全体のパフォーマンスをみるには、 time コマンドを使えばいいと思います。 perl 内部で実行時間を計るには、単純に、 time関数で時間を計る(秒単位)か、それで精度が足りない場合 Time::HiRes モジュール(CPAN)を使うとか あと、Benchmark モジュール(標準モジュール)を使うとか すればいいんじゃないかと思います。

polalis
質問者

補足

BLUEPIXY様、夜分にお返事ありがとうございます。 >die じゃなくて、単にexit を使って終了すればいいかもしれませんね。 dieとexitは動きが変わるんですか? ちなみにスカラ変数にメッセージをセットして、ログ関数の引数に変数を与えたら 「Died at スクリプト名」 が出力されてしまうんですね。。。 >読み込んだデータを変更して書き込む処理をしない場合 実行ログなんかもとりたいのですが、そういった場合の書き込む頻度が高い場合でも 必要ないですか? >もう一つイメージがわかないんですけど、 複数のCSVファイルを一気に読ませたいんです。 このスクリプト自体がサブルーチンだということは前に、ご説明したかと思いますが、 要はこれを何度も処理させることを、このスクリプト上で出来ませんでしょうか? それから $para1 = $ARGV[0]; $para2 = $ARGV[1]; $para3 = $ARGV[2]; $para4 = $ARGV[3]; $para5 = $ARGV[4];  ・  ・ 場合、簡略化して書く方法ってありますか? スミマセン、いつも質問攻めばかりでm(__)m

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

#2>下記のデータがどうしても、読めません。 読めないという状況をもう少し詳しく教えてください。 CSVデータが取り込めないということなのか、 関数がerr! を返すということなのか とか うまく行かない場合のパラメータも教えてください。 あと、 #2>ログ処理もバッチリです。 関数からdie を呼び出すようにすると、表示されるエラー行が、関数のdie を呼び出した行になりますが、それは、問題ないのでしょうか? なお、今日は、不在にするので、返事は遅くなるかも知れません。

polalis
質問者

補足

BLUEPIXY様、補足要求ありがとうございます。 大変スミマセン、自己解決しました。 何故エラー(err!)になってかというと、@ARVG[0]~[5]までしかスカラ変数に設定して いなかった為、パラメータが増えると読めてなかったみたいです。ゴメンナサイ。。。 ログ関数は、引数に渡されたMSG自体が書き込まれるという仕様ですよね。例えば変数に メッセージを仕込んでおいて、ログ関数の使用箇所によって変数を切り分ければいいわけですよね? 大丈夫です。ありがとうございます。 ところで迷惑ついでに、教えて頂きたいのですが、書き込む場合はロック処理 をしたほうがいいのはわかるんですが、読み込むときにも設置したほうがいいのですか? それと、メイン処理のOpenとcloseを繰り返して、負荷をかけた状態のパフォーマンスを みたいんですが、どうするのが効率的ですか?? print文にループかけただけでは、意味ないですよね。。。 度々、お力をお借りしてしまって申し訳ありませんが、よろしくお願いいたします。

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

すみません、#1ですが、ボケてました print squeezed(1,1,1,1,1);#XX は、最左列ですね。orz print squeezed(4,1,1,3,4);#YO とした時YO が得られないということですね。 さっき確認しました。 元のソースで CSVデータを読み込んでいるところで while(<IN>){ chomp; #この行を追加 のようにして下さい。 要するに、 最後のデータには、改行コードがついていたのでマッチしなかったということです。 chomp は、末尾に改行がある時それを削除する命令です。 すみませんでした。

polalis
質問者

補足

BLUEPIXY様、返事が遅くなりました。 いつも私の他力本願なお願いにお付き合い頂いて感謝しております。 chompの追記ならびに、ログ処理もバッチリです。 本当にありがとうございます。 ところで、ひとつ問題が起きてしまいましたので、またお聞かせください。 下記のデータがどうしても、読めません。ベースにしていたCSVに 1行加えただけなのですが… 読めてるデータの行を追加したりすると、読めなくなるパターンがあります。何故なのでしょう? 1,1,1,1,2,2,2,2,3,3,3,3 1,2,3,4,1,2,3,4,1,2,3,4 1:4,1:4,1:4,1:4,1:5,1:5,1:5,1:5,1:6,1:6,1:6,1:6 1:5,1:5,1:5,1:5,1:6,1:6,1:6,1:6,1:7,1:7,1:7,1:7 "1,3",2,4,1,"2,4",3,1,1,4,"2,3","2,3",1 1,2,3,4,1,2,3,4,1,2,3,4 TO,TO,TO,TO,WH,WH,WH,WH,LE,LE,LE,LE ちなみに私の環境では、@ARGVでパラメータを直打ち(ファイル名含め)で渡しているの ですが、これで動きが変わったりはしないですよね? お願いします。

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

>一番右の縦列をパラメータに指定すると何故だか値が割出せません。 うまくいかなくてすみません・ ですが 当方で試してみたところでは print squeezed(1,1,1,1,1); では、期待通り "XX" が返されます。 何か、質問者と当方で、扱っているデータが違うのではないかと思います。 先の質問で挙げられているデータと異なる場合、 データと試してみたパラメータを補足していただけますか? >Open関数にて「die」が選択されたときにlogに出力するというのをサブルーチンで、共通関数みたいな形にしたいのですがどうすればいいのでしょう? open(IN, "file") || die "ファイルのオープンに失敗しました"; みたいな話ですよね die が選択された時というより、 open が失敗した時 || 以降の命令が実行されるので、 open(IN, "file") || &myLogOut("file open error!"); みたいに置き換えて sub myLogOut { my $msg = shift; open(LOG, ">>err.log"); print LOG "$msg\n"; close(LOG); die $msg; } みたいな感じにすればいいと思います。

参考URL:
http://okwave.jp/kotaeru.php3?q=2242139

関連するQ&A

  • CSVから値の割り出し2

    お世話になります、Perl初心者です。 先日、同じような投稿を投げているのですが、完全に仕様を勘違い していて、また助言をして頂きたく投稿しました。 サンプルを送ってくれたBLUEPIXY様、すみません。 まずやりたい事は、アンケートのフォームからPOSTされた データをCSVファイルに突き合わせて、値を割り出すという ことなんですが… <CSVファイルの例> 1,1,1,2,2,2,3,3,3 1,2,3,1,2,3,1,2,3 1:3,1:3,1:3,3,1:2,3,1,2:3,1,2:3 "1,3","1,3",2,1,"2,3",1,"1,3",2,2 "A","B","C","-","D","-","E","F","G" 行は、設問の数だと想定して下さい。上からQ1,Q2…のような 感じです。英字の部分は結果(出力)になります。 ◆1:3は、1,2,3のどの値が入ってもというのを意味します。 ◆"1,3"は、1か3のどちらかという意味です。 ◆"-"はNullです。 渡されるパラメータは数字の1~3まで、設問数分一気に送られて きます。例)1,2,1,2,3… 渡されたパラメータを元に、上から値(範囲)を絞っていって 結果を返します(英字) 例) パラメータ「2,2,1,3」(1行目,2行目…)  結果「D」 これは、1行目をパラメータ「2」に対してマッチさせて 「2,2,2」の範囲を得ます。2つ目も「2」なので、1行目 の範囲の中から、ヒットする数値を割り出します。 それ以降も同じ要領で、絞っていき結果を出します(英字) このサンプルCSVだと、結果は2行目で決まってしまうの ですが、本来はもっと行が多いです。 恥ずかしい話なんですが、grepをしたらいいのか、 posで位置を得たらいいのか、lengthでバイト数を測れば いいのか、いい方法が思いつきません。 カンマやコロンでの処理が出来るのかどうかも解りません。 どうか、ご教授願えないでしょうか?

    • ベストアンサー
    • Perl
  • xlsの関数の計算範囲にバックグラウンドで値が更新されるcsvファイル

    xlsの関数の計算範囲にバックグラウンドで値が更新されるcsvファイルのセルを指定したいのですがいい方法はないですか csvファイルは開いてしまうと値が更新されません

  • CSVファイルをエクセルに取込むには

    VisualBasicで作成したCSVファイルをエクセルに取込み、ファイルの値を表示したいと考えています。 このとき、エクセルには既に枠(?表といった方がいいでしょうか?)が表示されており、CSVファイルのこの値は、表のこのカラムに表示すると言ったことがしたいのですが、どんな風に進めたら良いのか、全然イメージ出来ません。 こんな項目で調べたら?とか、こんな風に進めたら?とか、何かアドバイスをお願いします。

  • バッチでcsvファイルの指定のカラムを編集したい

    バッチでファイルの編集をしたい バッチファイルを使用して、csvファイルの読み込み~編集を行いたいと思っております 元ファイル:TEST_DATA.csv 内容: 111,222,333,444,555 123,456,789,321,987 上記のcsvファイルを読み込み、 ・5カラム目が987ならば3カラム目を654に変更する という処理を実行させたいのですが、 どのように行えばよいのでしょうか? 現在考えていることは、 1.for文を使用して指定のカラムを抜く(3カラム目と5カラム目を抜く)) 2.5カラム目の値をif条件に指定し、合致した場合、抜いた3カラム目の変数に654を入れる 3.654に変更した変数を3カラム目の値として入れる という順番で行えばいいと思っているのですが、 下記まで行ったところで行き詰ってしまいました for /F "tokens=3,5 delims=," %%i IN (TEST_DATA.csv) DO @(if %%j==987 set %%i=654 echo %i %j ) お分かりになられる方、ご教授願えませんでしょうか

  • 外部ファイルから特定の値を取り出して、値ごとに新しいファイルを生成して書き込むには?

    こんにちわ。質問させてください。 ひとつのCSVファイルがあります。1列目の先頭の値はランダムねアルファベットです。 aという値が先頭にある列は、a.csvを生成して、a.csvにaの行を書き込みます。b,cも同様にb.csv,c,csvを生成して書き込みます。 要するに一枚のファイルから値ごとに新しいファイルを生成して書き込みをしたいのです。新しくできたファイルは追加書き込みをしないでの上書きモードです。substr関数を使って値を取り出すまではわかるのですが、そこからの処理がわかりません。どうぞ教えてください。よろしくおねがいします。

    • ベストアンサー
    • Perl
  • csvファイルを使ってMySQLのテーブルを更新し

    約2万件ある15個のカラムで構成されるMySQLのテーブルがあります。 このテーブルをcsvファイルを使って更新しようと考えています。 csvファイルにはレコードIDとあるカラムの変更する値の2つのセルで 構成されています。 行数は毎回異なりますが、だいたい300行前後です。 csvファイルの具体的イメージはこんな感じです。 id order ============ 2,  200 4,  10 7,  460 11,  35 MySQLのテーブルの方にも「id」と「order」というカラムが存在します。 java や PHP を使ってやる方法はわかるんですが、プログラムを作成しないで SQLだけで行いたいと考えています。 LOAD DATA LOCAL INFILE などがあることがわかったのですが、レコードを REPLACE  するのではなく、一部のカラムをアップデートしたい、ということです。 どなたか、教えて頂けると助かります。 よろしくお願い致します。

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

  • vbs xlsをcsvに変換

    vbsでxlsファイルをcsvファイルに変換することは可能でしょうか。 手動で拡張子をcsvにすると、カンマ区切りではないため 一列目にすべての値がスペース区切りで出力されてしまいます。 vbsで実行可能でしたらコードのご教示頂けますでしょうか。

  • perlでCSVをソートする方法について

    perl初心者です。いつもありがとうございます。 perlでcsvファイル(1行のカラム数は200)、総行数は約3万行のファイルを37番目のカラム(-25以上25未満の数値データ)で降順ソートしその値によって行数がだいたい均等になるよう3分割し、2番目のカラムに文字でも数字でもよいのですがその4つのグループごとにフラグ(例えば1,2,3)を入れたいと思ってます。グループ化については境目の37番カラムの値は重複している場合が多いと思うのですがその場合は下(別に上でもかまいません)に入れるものとします。 ソートロジックは過去の質問を参照して理解しましたがグループ化しフラグを入れるルーチンがうまく作れません。下記のように作ったのですがこの先同じことを何度もやらなくてはならないので先に進めません。どなたかお助けください。最終的にやりたいことはカラム37でグループ化→カラム2にフラグを立てる、次にカラム2とカラム38(-25から0までの数値)でソートし同様に同じ行数になるようにグループ化→カラム3にフラグを立てる、さらにカラム2とカラム3とカラム39(-25以上25未満の数値データ)でソートし・・・同様に繰り返し最終的に1グループが100件(行)~150件(行)になるようにしたいのです。つまり約3万件のデータを3*4*2*4*2=192分割(5列の値で分類)したい、そしてどのような範囲で分割したかという情報も得たいのです。 use strict; use warnings; use utf8; use Encode; binmode STDOUT, ':encoding(utf-8)'; my $dir = './data'; # 処理するディレクトリ my $motoFile = 'customer.txt'; # もとファイル open my $fh, '<:encoding(cp932)', "$dir/$motoFile" or die 'ファイルが開けません。',"$!"; my %sorted; while (my $line = <$fh>) { my $key = (split /,/, $line)[37]; push @{$sorted{$key}}, $line; if (@{$sorted{$key}} == 1000) { open OUT, '>>:encoding(cp932)', "$dir/$key.tmp" or die "Can't open: $!"; print OUT @{$sorted{$key}}; close OUT; @{$sorted{$key}} = (); } } open OUT, '>:encoding(cp932)', "$dir/out.txt" or die "Can't open: $!"; foreach my $key (sort { $b <=> $a } keys %sorted) { if (-e "$key.tmp") { open IN, '<:encoding(cp932)', "$dir/$key.tmp" or die "Can't open: $!"; print OUT while <IN>; close IN; } print OUT @{$sorted{$key}} if @{$sorted{$key}}; } close OUT; #↓↓↓↓ここからフラグを作成するルーチン # 行数を調べ3つに分けるルーチン my @colum37; open IN, '<:encoding(cp932)', "$dir/out.txt" or die 'ファイルが開けません。',"$!"; my @in = <IN>; close IN; my $gyousuu = scalar(@in); my $amari = $gyousuu % 3; if ($amari == 0) { my $groupGyousuu = ($gyousuu-$amari)/3; print "総行数は$gyousuu","で、1グループの行数は$groupGyousuu","ほど、余りは$amari\n"; # あまりが0の時、group1は@inの0行 ~$groupGyousuu-1行まで #         group2は@inの$groupGyousuu行 ~$groupGyousuu*2-1行まで #         group3は@inの$groupGyousuu*2行~$groupGyousuu*3-1行まで foreach my $num (1..2) { push @colum37, (split /,/, $in[$groupGyousuu*$num])[37]; # これは境目の先頭の37番目 } print "@colum37\n"; #これでここまでは完成、分けるべき値がこの配列に入っている。 open OUT, '>:encoding(cp932)', "$dir/out.txt" or die "Can't open: $!"; foreach my $line (@in) { my @line = split /,/,$line; if ($line[37]>=$colum37[0]) { $line[1] = 1; }elsif ($line[37]>=$colum37[1] and $line[37]<$colum37[0]) { $line[1] = 2; }elsif ($line[37]<$colum37[1]) { $line[1] = 3; } $line = join (',',@line); print OUT $line; } close OUT; } elsif ($amari == 1) { この後未作成

    • ベストアンサー
    • Perl
  • CSVファイルのダウンロード

    よろしくお願いします。 現在、ボタンを押すと(=CGI実行)フィルターによりCSVファイルが作成されるという様なものを開発しております。 しかし、その出来上がったCSVファイルをそのままダウンロードしたいと言う要望がありまして、そのCGIに組み込めないものかといろいろ調べております。 概要 (1)ボタンを押す(=CGI実行) (2)フィルターによりCSVファイル作成 (3)作成されたファイルをダウンロード という具合で、教えていただきたいのは(3)です((1)(2)は作成済み)。 実際にはCSVファイルは3つできるのですが、これらをまとめてダウンロード・・・というのはムリですよねぇ(第1希望)。 ムリなら、処理の中で圧縮させます(これぐらいはできます)ので、そのファイルをダウンロードさせるというやり方でも構いません(第2希望)。 実現が難しいようであれば実行結果画面に<a href= ~>で貼り付けます。 webサーバー・・・HP-UX web・・・IE CGI開発言語・・・Perl 開発端末・・・windows2000(Tera Term 使用) 以上、情報等お持ちの方いらっしゃいましたら、 よろしくお願いいたします。

    • ベストアンサー
    • CGI

専門家に質問してみよう