- ベストアンサー
CSVから値の割り出し方法とは?
- アンケートのフォームからPOSTされたデータをCSVファイルに突き合わせて、値を割り出す方法を教えてください。
- CSVファイルの例を元に、渡されたパラメータを使って値の範囲を絞っていく方法を教えてください。
- grepやpos、lengthなどの関数を使ってカンマやコロンでの処理ができるのか教えてください。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
>>my @pos =(0 .. ($cols -1) );#有効な位置の配列、当初は0,1,2,3…列数-1 (15) >これは、どういう動きなんですか? これでやりたいことは、 @pos = (0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15); です。 こういう場合、 @pos = (0 .. 15); と書くことができます。(Perl が補ってくれます) 今対象としている、配列のデータ数は $cols に入っていて、これが16(読み込むCSVデータで変わる)です。 配列の添字は0~15(要素数-1)なので、 @pos =(0 .. ($cols -1) ); としています。 ちなみに"($cols -1)" の部分は、カッコで囲む必要はありませんが、演算子の優先順位がわかりにくい時(調べるのがめんどい)とかくくりをわかりやすくするために書いてあります。 >>my $i,@wk; >それから、この部分は単純にレキシカル変数の$iと@wkを宣言してるという意味なんですか? そうです。単に変数を準備しているだけです。 my $i; my @wk; としても同じです。書いているように、一行にできます。 >>my ($para, @data) = @_; >>my $i,$len=@data; >実際、各変数にはどういった値が格納されているんですか? my ($para, @data) = @_; の右辺、@_ は、関数で受けた引数の並びが入っている配列です。 左辺(変数, 変数) は、リストです。 リストは、右辺において、配列の初期化などに使われますが、 (例えば、@data = (1,2,3) のようなこと) 左辺に置いてそれぞれの要素に代入させることができます。 例えば ($first,$second)=(1,2); は、 $first=1; $second=2; と同じ動作になります。 そこで、 ($para, @data) = @_; のようにした場合、 配列 @_ の最初の要素が$para に入り、残りの全ての要素が@data に入ります。 順序を逆にして、例えば (@data,$para) = @_; のようにすると 最初の@data が全ての要素を取ってしまいますから、 $para に要素は代入されません。 関数で呼び出す時、 func($para, @data); のように呼び出したとき、 $para と @data のように別々の引数があるというのではなくて、 関数の引数に配列を渡した場合は、例えて言うならその中身がそれぞれのバラバラの引数に展開されて1つの配列(@_ )になるので、 func($para1, @data1,$para2, @data2); とかしたら、引数を受け取る関数側では、一緒くたになってしまうので、区別はできません。 my ($para1, @data1,$para2, @data2)=@_; のようにはできないです。 (@data1 が以降のデータを全て取ってしまう。) $len=@data; 単純変数=配列; のようにした場合、(ここでいう単純変数は、スカラーといいます。単に値を保持する変数のことです) 単純変数には、配列の要素数が代入されます。 (スカラーが要求される場面で配列を使うと要素数が返されます) 例えば、 @data =(1,3,5,7,10); の場合 $len = @data; とすると$len には、5 が入ります >お薦めする参考書等ってなにかありますか? サイエンス社の「新Perlの国へようこそ」が良くまとまっていて良いです。 あとは、定番ですが、 オライリーの「Perlクックブック」(2分冊) には、色々なサンプルが載っているので大変参考になります。 余裕があれば オライリーの「プログラミング Perl」(2分冊) ソフトバンク「Perl プログラム」 とか読むといいかもしれません(かなり根性が必要?) ---------------------------------------------------------------- ちなみに use Text::CSV; は、標準モジュールではない(CPANモジュール)ので、 別途インストールする必要があります。 ActivePerl を使っているならppm ツールを用いて簡単にインストールできます。
その他の回答 (4)
- BLUEPIXY
- ベストアンサー率50% (3003/5914)
use Text::ParseWords; #標準モジュール @data=();#読み込んだデータの格納用 open(IN, "data.csv"); while(<IN>){ @fields = quotewords("," => 0 , $_); #カンマ区切りのデータを@fields に取り込む foreach $field (@fields){ if(index($field, ":")>=0){ #:がある場合、1:3→[1-3]のように変換する $field =~ s/:/-/; $field = "[$field]"; } elsif(index($field, ",")>=0){ #,がある場合1,3,4→1|3|4のように変換する $field =~ s/,/\|/g; } } push @data, [@fields]; } close(IN); $rows = @data; $cols = @{$data[0]}; #$data[行][列] 同じ $data[行]->[列] print squeezed(4,2,3,4,1);#パラメータから絞り込む、(この場合、AA) sub squeezed { my @para = @_ ; my @pos =(0 .. ($cols -1) );#有効な位置の配列、当初は0,1,2,3…列数-1 (15) my $i,@wk; for($i=0;$i<$rows-1;$i++){ @wk = (); foreach my $p (@pos){ #有効な位置だけを調べる if($para[$i] =~ /$data[$i]->[$p]/){ push @wk, $p; #パターンにマッチする位置を配列に保存 } } @pos = @wk; } if(@pos == 1){ # 結果残った位置は1つだった return $data[-1]->[$pos[0]]; } else { return "err!";# 0個だったり、2個以上だったらエラー } }
お礼
BLUEPIXY様、何度もありがとうございます。 スゴイです。ちゃんと想定どおりに動きます。 こんなことが出来るんですね。本当に助かりました。 そこで質問なのですが >my @pos =(0 .. ($cols -1) );#有効な位置の配列、当初は0,1,2,3…列数-1 (15) これは、どういう動きなんですか?コメント書いてあるのに 理解できない自分が恥かしいのですが… >my $i,@wk; それから、この部分は単純にレキシカル変数の$iと@wkを宣言してるという意味なんですか? あと、前回頂いたセレクトする関数の動きもよくわからなかったのですが >my ($para, @data) = @_; >my $i,$len=@data; 実際、各変数にはどういった値が格納されているんですか? 最後に、BLUEPIXY様がお薦めする参考書等ってなにかありますか? 度々申し訳ありませんが、ご教授ください。 お願い致します。
- vsba23895
- ベストアンサー率58% (18/31)
「パラメータ」を、「ヒット」するフィールドの有効フラグを消すために使って行けばいいのでは ? @is_valid を有効フラグにして ------------------ use strict; use Text::CSV; my $csv= Text::CSV->new(); my @target_list= (2,2,1,3); my @is_valid; my @field_list; while(<>) { chomp; if (my $OK= $csv->parse($_)) { @field_list= $csv->fields(); last unless(scalar(@target_list)); my $target= shift(@target_list); my $n_field= 0; foreach my $field (@field_list) { if (!(defined $is_valid[$n_field]) || $is_valid[$n_field]) { $field=~ s/1:3/1,2,3/; $is_valid[$n_field]= (grep(/$target/,$field))? 1 : 0; } $n_field++; } } } my @result_list; foreach my $flag (@is_valid) { my $field= shift(@field_list); push(@result_list,$field) if($flag); } print "result:",join(',',@result_list),"\n"; --------------------- あらゆるエラー処理を無視してます。(CSV が壊れていたり、データが「パラメタ」の行数より少なかったり…)。あくまでコンセプトとして。 #うーん、インデントが消えて見にくいですね
補足
vsba23895様、ご回答ありがとうございます。 >「パラメータ」を、「ヒット」するフィールドの有効フラグを 消すために と言われてるのは、どういうことを示唆しているのでしょうか? 当方、開発経験が浅いため、意味がきちんと理解できません。 それから、コマンドラインから実行すると「use Text::CSV; 」の行で、エラーが起きてしまいます。 <Can't locate Text/CSV.pm in @INC> お手数でなければ、ご教授いただけませんか?
- BLUEPIXY
- ベストアンサー率50% (3003/5914)
補足ありがとうございます。 あともう一つ、CSVデータのパターンで 例えば "1,3:4" のようなパターンがある場合はありますか? "1,3,4" が必ず使われると考えていいのでしょうか?
補足
そうですね。 CSVのパターンは必ず"1,3,4"となります。 よろしくお願いします。
- BLUEPIXY
- ベストアンサー率50% (3003/5914)
>本来はもっと行が多いです。 とりあえず、本来の場合というのを補足していただけないでしょうか? 質問文の例だと、1行目と2行目のパターンから、必ず2行のデータで結果が決まってしまいます。 そうすると、以下のCSVのデータもパラメータも不要だということになります。 あと、絞られた範囲に該当するパラメータが存在しない場合は、何を返すのでしょうか?
お礼
補足追加です。 1行目で「1」を選んだときの結果(英字)は、どう見ても 一緒ですよね。 これは、まず将来的に値が変動する可能性があるということと、 2行目以降の質問に対して(1行目含め)、どの答えを選択したか ということの平均値を取る予定があるためです。 (このサンプルは仕上がってます。) 私のスキルでは、かなり難解なのでよろしくお願いいたします。
補足
BLUEPIXY様 補足要求ありがとうございます。 仰る通りですね。 これでは、サンプルになりませんよね…。 現行のサイズ的には、下記のような感じになると思います。 実際の値も、こんな感じです。() ただCSVファイル自体は行や列が、追加されたり削除されたり する可能性があるのでサイズは変動します。 各行の数値の最高値で、選択肢の数はわかると思います。 CSVファイル: 1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4 1,1,2,3,1,3,3,2,1,2,3,1,2,2,3,1 1:3,1:3,4,4,1:2,3,4,1:2,1,2:4,2:4,2:4,2:3,4,2:3,1 "1,3,4",2,2,2,1,1,3:4,3:4,"2,4","2,4",1,3,"2,4",1,3,3 1:4,1:4,1:4,1:4,1,2,3,4,1:2,1:2,3,4,1,1,2:3,4 XX,XX,XX,XX,SI,QU,SS,"-",OP,OP,AC,"-",AA,AA,"-",YO 基本的には、該当しないというのはありえないはずなんですが 万が一、該当値がない場合はエラーを返す予定です。 ※Null値("-")に関しては、フォーム側で対応する予定ですので プログラム的には、Nullが解る値を返します。 以上です、よろしくお願い致します。
お礼
BLUEPIXY様、いつも遅い時間になってしまってスミマセン。 そして、感謝感激です。 これ以上にない程の解説をして頂いて、言葉が見つかりません。 オライリーの参考書は、周りの人からも評判がいいと薦められました。 少し、お金がかかってしまいますけどね…。 でもBLUEPIXY様が薦められるなら、頑張って読んで勉強しようと思います。 この度は、本当にありがとうございました。 まだまだ教えて頂きたいことは山ほどありますが、引きずってしまっては申し訳 ありませんので、それはまた次の機会にお願いします。 とても勉強になりました。