- 締切済み
csvの内容を配列に入れて個別に変数をつける
はじめまして、お世話になります。 内容はdata.csvを開いて$a1の値が、ban1の時に、 該当の一行を読み出して、カンマ区切りでわかれている順番に、 $a1 $a2 $a3という変数に代入して他のプログラム内で、利用できればと思いますが、 思うように値が取得できません。 下記、参考サイトなどを見ながら、 動作の部分をかいてみました。 まだ理解が浅く、見当はずれな指示があるかもしれませんが、 ご参照いただき具体的な、 ご指摘をいただければと思います。 よろしくお願いいたします。 my $dataFile = 'data.csv'; open FH,"<$dataFile" or error_msg("データファイルが開けません : $!"); flock(FH, LOCK_EX); while(<FH>){ chomp(); my@dummy = split(/,/,$_); if($a1 == $ban1) { $hoge = $_; last; } chop $hoge; ($a1,$a2,$a3,$a4,$a5,$a6,$a7,$a8,$a9,$a10,$a11) = split(/,/); } flock(FH, LOCK_NB); close FH;
- みんなの回答 (5)
- 専門家の回答
みんなの回答
- Ogre7077
- ベストアンサー率65% (170/258)
簡単ながら # ファイルを全部読み取り my @records; my $dataFile = 'data.csv'; open FH, "<$dataFile" || die; foreach(<FH>) { chomp(); my @a = split /,/; push @records, \@a; } close FH; # 読み取った行を繰り返し my $size = @records; for (my $i = 0; $i < $size; $i++) { if ($records[$i]->[0] eq 'ban1') { my @a = @{$records[$i]}; &他のプログラムの処理(@a); if ($i + 2 < $size) { my $b = $records[$i+2]->[3]; &任意の行から読み取った値を処理($b); } } }
- Tacosan
- ベストアンサー率23% (3656/15482)
配列使ったら?
- ORUKA1951
- ベストアンサー率45% (5062/11036)
質問でされたいことが明白でないのですが・・。条件を後出しで追加しないで下さい。 CSVの先頭にkeywordを含む行を見つけて配列@aに入れて、配列の要素を参照するのでしたら$a[0]でよい事は前回説明しました。 ところが補足では複数行になっています。複数行の場合は、配列の配列になりますから、 my(@A, @tmp); while (<>) { @tmp = ********** と配列に代入 push @A, [ @tmp ]; } として、外から $A[2][3] になります。 このあたりは、基本的な処理になりますので、「プログラミングPerl」などの書籍を求められて、学ばれるほうが良いですよ。 Perlですから、様々な方法が取れます。--長所でもあり欠点
- ORUKA1951
- ベストアンサー率45% (5062/11036)
>下記、参考サイトなどを見ながら、 splitを使っているだけであまり参考にならないようですね。 if($a1 == $ban1){} といきなり現れても$a1も、その値も未知 要は、行の先頭がban1の時に、各値を代入すればよい。 なお、csvはそれを作成したアプリケーション依存です。例えば各項の値に,が値として含まれていたときの処理などを加えなければなりません。(split(/,/,$_);は使えない) excelの場合、値に,や"や改行が含まれている場合は値が""で括られます。 値にがある場合は""に置き換えられています。 それを取り出した後、,や""は再びもとの形に戻さなければなりません。 もう一点、値に改行が含まれていると困りますので 下記参考に! タブは に置換してあるので戻す。 my $check = 'ban1'; while (my $line = <FH>) { $line .= <FH> while ($line =~ tr/"// % 2 and !eof(FH)); if($line =~ /^$check,/ ){ $line =~ s/(?:\x0D\x0A|[\x0D\x0A])?$/,/; my @a = map {/^"(.*)"$/s ? scalar($_ = $1, s/""/"/g, $_) : $_}($line =~ /("[^"]*(?:""[^"]*)*"|[^,]*),/g); # $a[0]~ いくつでも参照できるのでそれを使う。 }
お礼
ORUKA1951様 ご回答いただきありがとうございます。 エクセルでのデータの扱いも、 処理の中に考慮する必要があるのですね。 とても勉強になりました。 ご教示いただいた内容で、試してみます。 ありがとうございました。
補足
ORUKA1951様 お世話になっております。 先ほどはご回答ありがとうございました。 my $check = 'ban1';での該当した行を取得していますが、 任意の行、たとえば3行目の4列目を取得することは可能なのでしょうか? $a[2][3]で試しましたが、エラーが出てしましました。 何か追加すべき必要な処理がございましたら、 ご教授いただければありがたいです。 よろしくお願いいたします。
- Tacosan
- ベストアンサー率23% (3656/15482)
とりあえず ・「$a1」とは何か ・「該当の一行」とはどこか ・「他のプログラム」とは何か が分からない. 配列じゃダメなの?
補足
Tacosan様 わかりにくい質問で申し訳ございませんでした。 質問内容の補足をいたします。 >・「$a1」とは何か こちらは参照するcsvファイルの1行にある列のことです。 a1が1行目、1番の列の項目で、1行に列は11項目あります。 1行目の11項目を分割して、 a1から、$a11の変数に代入できればと思っています。 >・「該当の一行」とはどこか こちらはif($a1 == $ban1)のことで、 1行目の一番目の項目が$ban1とマッチした行になります。 >・「他のプログラム」とは何か csvファイルを開いた後に、 a1 b1 等の各行頭の値を、プルダウンフォームに入れてみようと思っています。 以上、よろしくお願いいたします。
補足
ORUKA1951様 ご回答いただきありがとうございます。 条件につきましては申し訳ございませんでした。 複数行の場合、配列の配列に入れることが 必要だという事は大変参考になりました。 書籍を購入し勉強しようと思います。 未熟な私に助言をいただき、誠にありがとうございました。 下記の方法で値を取得することができました。 ただ、こちらの方法だと、項目が増えるのに従い、 追記の作業も増えそうなので、 もう少しスマートな方法で値を取得・代入できないものでしょうか? よろしくお願いいたします。 open(IN,"data.csv") or die; my @data=<IN>; close(IN); $num=@data; foreach(@data) {($m1,$m2,$m3,$m4,$m5)=split(/,/,); push(@data0,"$m1"); push(@data1,"$m2"); push(@data2,"$m3"); push(@data3,"$m4"); push(@data4,"$m5"); $mname1 = @data4[1]; $mname2 = @data4[2]; $mname3 = @data4[3]; chomp($mname1); chomp($mname2); chomp($mname3); $mname1 =~ s/[\n\r]//g; $mname2 =~ s/[\n\r]//g; $mname3 =~ s/[\n\r]//g; }