解決方法:CSVデータを絞り込むサブルーチンの修正方法

このQ&Aのポイント
  • CSVデータを絞り込むサブルーチンの修正方法について解説します。
  • 最終行のみ変更を加えないようにする方法を説明します。
  • サブルーチンの理解が難しい場合は、他の方法を検討することもあります。
回答を見る
  • ベストアンサー

サブルーチンの結果

my @data; my ($rows,$cols); sub Gettest { use Text::ParseWords; my $dfile = shift; # CSVファイル my @array = @_; @data = (); open(IN, $dfile) or exit(-1);# while(<IN>) { chomp; my @fields = quotewords("," => 0 , $_); # カンマデータの取込 foreach my $field (@fields){ if(index($field, ":") >= 0) { my @range = split(':',$field);# 範囲の取出し $field = sub { my $v = shift; return $range[0] <= $v && $v <= $range[1];}; } elsif(index($field, ",") >= 0) { my @list = split(',',$field); #種類の取出し $field = sub { my $v = shift; return grep($v == $_, @list); };}} push @data, [@fields];} close(IN); $rows = @data; $cols = @{$data[0]}; return squeezed(@array);#// 該当範囲の絞り込み} sub squeezed { my @para = @_; my @pos = (0 .. ($cols -1)); my $i; my @wk; for($i = 0; $i < $rows -1; $i++) { @wk = (); foreach my $p (@pos) {# 有効な位置 my $test = $data[$i]->[$p]; if("CODE" eq ref($test)){ # 範囲テストコードの場合 push @wk, $p if &$test($para[$i]); # test がOK } elsif($para[$i] eq /$test/) {push @wk, $p; # マッチ位置を配列に}} @pos = @wk;} if(@pos == 1){ return $data[-1]->[$pos[0]]; } else {return undef;#// 該当なしか2個以上ならundefを返却 }}1; 引数によってCSVデータの範囲を絞って結果を返すといった関数を、ご提供して頂いた のですが、「1:4」や「1,3,4」等の答えがCODE(XXX)になってしまいます。ご提供者様から、ループで変換するのではなく 最終行のみ変更を加えないようにするというアドバイスを頂いて色々ためしてみたのですが、 私のレベルではサブルーチンの理解が出来なくて全然うまくいきません。他力本願な お願いで申し訳ないのですが、解る方教えて下さい。

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

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

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

#5>そんなに違うものなんですか??? [ quotewords("," => 0, $lines[@lines-1]) ] は、1行分のデータの無名配列です。 なので、これをpush していくと $data[0]=[1行目のデータ]; $data[1]=[2行目のデータ]; … となります。 quotewords("," => 0, $lines[@lines-1]) は、配列なので、 push @data, 配列 とすると、 $data[0]= 1個目のフィールド; $data[1]= 2個目のフィールド; … というようになり、 @data には、各行のデータを入れたいのに、各列のデータが入ってしまいます。 #5>「1:3」や「7:12」とかのデータを「1,2,3」や「7,8,9,10,11,12」などに変換するやり方 既にやってるように、 1:3 から $v1 = 1; $v2 = 3; の様に取り出せたら @array = ($v1 .. $v2); のようにすれば 1,2,3 の配列になります。 "1,2,3"の文字列が必要ならさらに $atext = join(',', @array); とすればいいです。

polalis
質問者

お礼

BLUEPIXY様 私の他力本願なお願いに最後まで付き合ってくれて、ありがとう ございました。 なるほど…レコードを扱わなければいけないのに、フィールドを Pushしてたんですね。 >「1:3」や「7:12」とかのデータを「1,2,3」や「7,8,9,10,11,12」 これも扱っていましたね^^; 丁寧に説明してくださって、とっても解りやすかったです^^ ありがとうございました。

その他の回答 (5)

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

#4を修正してみました。 my @data; my $rows; my $cols; #sub Gettest { use Text::ParseWords; my $dfile = shift; # CSVファイル #my @array = @ARGV; @data = (); # 配列の初期化(読み込んだデータの格納用) open(IN, $dfile) or exit(-1);# データファイルの読込み #while(<IN>) { #chomp; @lines = <IN>; chomp @lines; foreach (@lines[0..(@lines-2)]){ my @fields = quotewords("," => 0 , $_); # カンマ区切りデータの取り込み foreach my $field (@fields){ if(index($field, ":") >= 0) { my @range = split(':',$field);# 範囲の取り出し $field = sub { my $v = shift; return $range[0] <= $v && $v <= $range[1];}; } elsif(index($field, ",") >= 0) { my @list = split(',',$field); #種類の取り出し $field = sub { my $v = shift; return grep($v == $_, @list); }; } } push @data, [@fields]; } close(IN); push @data, [ quotewords("," => 0, $lines[@lines-1]) ]; $rows = @data; $cols = @{$data[0]}; #return squeezed(@array);#// 該当範囲の絞り込み $val = squeezed(@ARGV);#// 該当範囲の絞り込み print $val; #} sub squeezed { my @para = @_; my @pos = (0 .. ($cols -1)); my $i; my @wk; for($i = 0; $i < $rows -1; $i++) { @wk = (); foreach my $p (@pos) {# 有効な位置だけ調べる my $test = $data[$i]->[$p]; if("CODE" eq ref($test)){ # 範囲テストコードの場合 push @wk, $p if &$test($para[$i]); # test がOK } elsif($para[$i] eq $test) { push @wk, $p; # マッチした位置を配列に保存 } } @pos = @wk; } if(@pos == 1){ #// 結果算出 return $data[-1]->[$pos[0]]; } else { return undef;#// 結果が該当なし、もしくは2個以上ならundefを返却 } } #1; ---------------------------------------------------------------- あと、test1.csv も test2.csv も最終行の前までに値が1つに決まりません。 (3行目が1:12 の為に全てがそれまでの該当し、4行目の時点で2つ該当するモノがあるため)

polalis
質問者

補足

BLUEPIXY様 長い間、ありがとうございました。 本当に、本当に助かりました^^ そして、使えないテストデータを送ってしまって 申し訳ありません。。。。 ところで、 push @data, [ quotewords("," => 0, $lines[@lines-1]) ]; と @aaa = quotewords("," => 0 ,@lines[@lines-1]); push @data, @aaa; は、そんなに違うものなんですか??? あ、あと「1:3」や「7:12」とかのデータを 「1,2,3」や「7,8,9,10,11,12」などに変換するやり方 はありますか??

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

#3>上記の処理フロー自体が間違っているのでしょうか??? 変更した、プログラム、 テストに使用したデータ、パラメータ を補足していただけますか?

polalis
質問者

補足

<プログラム> $aaa = @ARGV[1]; $bbb = @ARGV[2]; $ccc = @ARGV[3]; $ddd = @ARGV[4]; $eee = @ARGV[5]; $fff = @ARGV[6]; $ggg = @ARGV[7]; my @data; my $rows; my $cols; #sub Gettest { use Text::ParseWords; my $dfile = shift; # CSVファイル my @array = ($aaa,$bbb,$ccc,$ddd,$fff,$ggg); @data = (); # 配列の初期化(読み込んだデータの格納用) open(IN, $dfile) or exit(-1);# データファイルの読込み #while(<IN>) { #chomp; @lines = <IN>; chomp @lines; foreach (@lines[0..(@lines-2)]){ my @fields = quotewords("," => 0 , $_); # カンマ区切りデータの取り込み foreach my $field (@fields){ if(index($field, ":") >= 0) { my @range = split(':',$field);# 範囲の取り出し $field = sub { my $v = shift; return $range[0] <= $v && $v <= $range[1];}; } elsif(index($field, ",") >= 0) { my @list = split(',',$field); #種類の取り出し $field = sub { my $v = shift; return grep($v == $_, @list); }; } } push @data, [@fields]; } close(IN); @aaa = quotewords("," => 0 ,@lines[@lines-1]); push @data, @aaa; $rows = @data; $cols = @{$data[0]}; #return squeezed(@array);#// 該当範囲の絞り込み $val = squeezed(@array);#// 該当範囲の絞り込み print $val; #} sub squeezed { my @para = @_; my @pos = (0 .. ($cols -1)); my $i; my @wk; for($i = 0; $i < $rows -1; $i++) { @wk = (); foreach my $p (@pos) {# 有効な位置だけ調べる my $test = $data[$i]->[$p]; if("CODE" eq ref($test)){ # 範囲テストコードの場合 push @wk, $p if &$test($para[$i]); # test がOK } elsif($para[$i] =~ /$test/) { push @wk, $p; # マッチした位置を配列に保存 } } @pos = @wk; } if(@pos == 1){ #// 結果算出 return $data[-1]->[$pos[0]]; } else { return undef;#// 結果が該当なし、もしくは2個以上ならundefを返却 } } #1; <test1.csv> 1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4 1,1,2,2,3,3,4,4,1,1,2,2,3,3,4,4,1,1,2,2,3,3,4,4,1,1,2,2,3,3,4,4 1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12 1:2,3:4,1:2,3:4,1:2,3:4,1:2,3:4,1:2,3:4,1:2,3:4,1:2,3:4,1:2,3:4,1:2,3:4,1:2,3:4,1:2,3:4,1:2,3:4,1:2,3:4,1:2,3:4,1:2,3:4,1:2,3:4 <test2.csv> 1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4 1,1,2,2,3,3,4,4,1,1,2,2,3,3,4,4,1,1,2,2,3,3,4,4,1,1,2,2,3,3,4,4 1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12,1:12 "1,4","5,9","1,4","5,9","1,4","5,9","1,4","1,4","1,4","5,9","1,4","5,9","1,4","5,9","1,4","1,4","1,4","5,9","1,4","5,9","1,4","5,9","1,4","1,4","1,4","5,9","1,4","5,9","1,4","5,9","1,4","1,4" どのパラメータでも、答えが返ってきません。。 宜しくお願い致しますm(__)m

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

#2>やはりうまくいきません。。。。 実際に動かして試してはいないんですけど・ while(<IN>) { chomp; の部分を @lines = <IN>; chomp @lines; foreach(@lines){ my @fields = quotewords("," => 0 , $_); } に置き換えたわけですよね。 この場合、最後の } が要りませんね。 while での<IN> が foreach での @lines に変わったわけですので あと、 foreach(@lines){ だと、全部の行を処理することになるので、ここで最終行を除くループにする必要があります。 foreach my $field (@fields[0..(@fields -2)]){ の@fields は、一行のデータをカンマでフィールドに分けた配列のことですから見当違いです。 基本的に元のプログラムで、 while(<IN>) の入力が $_ になっている部分が foreach(@lines) で $_ になっていれば その最終行の処理の変更以外は、元のプログラムを変更する必要はありません。 まずは、元のプログラムと同じ流れになるように変更して、 最終行の場合どこで変更すればいいかを考えるといいと思います。

polalis
質問者

補足

BLUEPIXY様、アドバイスありがとうございます。 何度も聞いてしまって申し訳ないのですが、また 質問させてください。 @lines[@lines-1]が最終行になるわけですよね? @lines[0..(@lines-2)]に対して、ループ処理をしたあと 列数($cols)と行数($rows)を取得する前に 最終行にquotewordsとchompを処理して新たな配列を作成し @dataにpushしたのですが、答えが戻ってきません。 (「:」や「,」を使っていないデータも含め) エラーコードが返ってくるわけではないのですが、、、 上記の処理フロー自体が間違っているのでしょうか???

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

>読込ループで変換するのではなく最終行のみ変更を加えないようにする 簡略化して書くと、ファイルを読込ながらする処理は、 例えば、 open(IN, "読込ファイル"); while(<IN>){ #$_ に対する処理 } close(IN); の様になります。 ファイルからの読込時に処理するのではなくて、 いったん全部読み込んでから処理する場合、 open(IN, "読込ファイル"); my @lines=<IN>; #配列に全部読み込む close(IN); foreach (@lines){ #$_ に対する処理 } とすれば同じになります。 ここで、最終行を除く場合は、 例えば foreach (@lines[0..(@lines-2)]){ #$_ に対する処理 } のようにすればいいです。 (質問のプログラムの場合、chomp と quotewords の処理は、最終行にも行う必要があります) もしくは、 my $len = @lines ; で読み込んだファイルの行数がわかるので、 $_ の代わりに $lines[$n]のようにして、for 文で、まわして $n が$len -1 (最終行)でないかどうか調べて、処理を分けるようにすればいいでしょう。

polalis
質問者

補足

BLUEPIXY様、ご回答ありがとうございます。 何度もお手数かけて本当に申し訳ないのですが、やはりうまくいきません。。。。 下記のようにしてみたのですが、結果が戻ってきません。 なにがいけないのでしょうか?? そしてスクリプト上で何をやっているのか書いてみました。 わからないとこも多々あり、意味がおかしいとこも指摘してくださると助かります。 $aaa = @ARGV[1]; $bbb = @ARGV[2]; $ccc = @ARGV[3]; $ddd = @ARGV[4]; $eee = @ARGV[5]; $fff = @ARGV[6]; my @data; my $rows; my $cols; #sub Gettest { use Text::ParseWords; my $dfile = shift; my @array = ($aaa,$bbb,$ccc,$ddd,$eee,$fff); @data = (); open(IN, $dfile) or exit(-1);#(1)ファイルの読み込み #while(<IN>) { #chomp; @lines = <IN>;#(2)読み込んだファイルを配列へ chomp @lines;#(3)行末の改行削除 foreach(@lines){#(4)@lineのデータを$_に順番に入れる my @fields = quotewords("," => 0 , $_);#(5)$_のデータのカンマ区切りを配列へ } foreach my $field (@fields[0..(@fields -2)]){#(6)配列の最終行以外を$filedへ順番に入れる if(index($field, ":") >= 0) {#(7)":"が0個以上あれば my @range = split(':',$field);#(8)配列に":"を区切りにして格納 $field = sub { my $v = shift; return $range[0] <= $v && $v <= $range[1];};#(9)$range[0]~[1]の範囲を求める } elsif(index($field, ",") >= 0) { my @list = split(',',$field);#(10)","が0個以上あれば $field = sub { my $v = shift; return grep($v == $_, @list); };#(11)配列から$vを検索 } push @data, [@fields];#(12)配列(リスト)を配列の末尾へ } close(IN); $rows = @data;#(13)要素数を求める $cols = @{$data[0]};#(14)列の長さ、、、リファレンス??? $val = squeezed(@array);#// 該当範囲の絞り込み print $val; #} sub squeezed { my @para = @_; my @pos = (0 .. ($cols -1));#(15)列のサイズを配列へ my $i; my @wk; for($i = 0; $i < $rows -1; $i++) {#(16)行数分カウントアップしながらループ @wk = (); foreach my $p (@pos) {# (17)有効な位置だけ調べる(???) my $test = $data[$i]->[$p]; if("CODE" eq ref($test)){ #(18)変数がサブルーチンの戻り値以外なら(???) push @wk, $p if &$test($para[$i]); #(19)??? } elsif($para[$i] eq /$test/) {#(20)変数(配列)が$test以外なら?? push @wk, $p; # マッチした位置を配列に保存 } } @pos = @wk; } if(@pos == 1){ #// 結果算出 return $data[-1]->[$pos[0]]; } else { return undef;#// 結果が該当なし、もしくは2個以上ならundefを返却 } } #1;

  • osamuy
  • ベストアンサー率42% (1231/2878)
回答No.1

てっとりばやく最終行を1行めにもってきて、 $_ = <IN>; chomp; my @answer = quotewords("," => 0 , $_); # 回答行を取得。残りの行を@dataに。 while ( <IN> ){ chomp; # 以下略。 として、 return $#pos == 0 ? $answer[ $pos[0] ] : undef; ――みたいにするとか。

polalis
質問者

補足

osamuy様、 アドバイスありがとうございます。 早速、試してみたのですが「1:4」「1,3,4」以外の普通の答え(英数字)も返ってこないみたいです… 私自身でも最初にファイルを読み込んで、popして最後にpushして…みたいなことを 色々試しているのですが、リファレンスの概要をきちんと理解していないため、サブルーチンの中の サブルーチンの動きが全然わかりません。。。 とても困っているので、解るようでしたら是非ご教授願えないでしょうか???

関連するQ&A

  • 教えてください

    何度もこちらでお世話になっております。どうしてうまくいかないのか、教えて下さい。 下記csvファイルは問題ないのですが、それ以外を引数に与えると結果が表示されません。 概要:アンケート  ≪test.html≫ ※設問ファイル 質問1~5(3択)まである ≪test.cgi≫ ※結果表示 &ReadParseを使用 @pairs = ($in{'q1'},$in{'q2'},$in{'q3'},$in{'q4'},$in{'q5'}); $values = Gettest("data1.csv",@pairs); print $values,"\n"; ≪test.pl≫ ※サブルーチン sub Gettest { use Text::ParseWords;  #// 標準モジュール my @array = @_; my $dfile = shift @array; #// CSVファイル @data = (); #// 配列の初期化(読み込んだデータの格納用) open(IN, "$dfile") or exit; #// データファイルの読込み while(<IN>) { chomp; @fields = quotewords("," => 0 , $_); #// カンマ区切りデータの取り込み foreach $field (@fields){ if(index($field, ":") >= 0) { $field =~ s/:/-/; #// データの整形(1:3→[1-3]) $field = "[$field]"; } elsif(index($field, ",") >= 0) { $field =~ s/,/\|/g;#// データの整形(1,3,4→1|3|4) }} push @data, [@fields]; } close(IN); $rows = @data; $cols = @{$data[0]}; $values = squeezed(@array);#// 該当範囲の絞り込み return "$values\n"; exit; sub squeezed { my @para = @_; my @pos = (0 .. ($cols -1)); 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){ #// 結果算出 return $data[-1]->[$pos[0]]; } else {return exit;#// 結果が該当なし、もしくは2個以上ならエラーを返却 }}} 1;

    • ベストアンサー
    • Perl
  • 二次元配列に値をセットしたいんですが

    ASP(html)での変数をJavaScriptに渡して 二次元配列を作成したいのですが、どうもうまくいきません。 どなたか、ご教授願います。 サンプル 変数:strFact = "'工場1', 1000, 20/'工場2', 500, 90/'工場3', 2000, 100/'工場4', 900, 10" -------------------JavaScript strFact_WK = <%=strFact %>  ※1 var test = new Array(); var rows = strFact_WK.split("/"); for( var i in rows) { test.push(new Array()); var cols = rows[i].split(","); for( var j in cols) { test[i].push(cols[j]); } } ---------------------- 当然ですが、 ※1の所で strFact_wk = "'工場1', 1000, 20/'工場2', 500, 90/'工場3', 2000, 100/'工場4', 900, 10" とすると作成されます。

  • サブルーチン内のサブルーチン定義について

    サブルーチン内で定義したサブルーチンで、思い通りにならない挙動で困っています。 'test'を10万回繰り返す文字列の生成を行い、その文字列長を表示する関数を funcA とします。その生成過程では、自分の関数内で宣言した再帰関数 funcB を呼び出します。 #! /usr/local/bin/perl use strict; my $time0; for(my $i=0; $i<10; $i++){   $time0 = times();   &funcA();   print((times() - $time0). "\n"); # funcAに掛かった時間 } sub funcA {   my $buffer = '';   &funcB(1);   print length($buffer) . " : "; # $buffer の文字列長      sub funcB{     my $n = shift;     $buffer .= 'test';     return if($n==100000);     funcB($n+1);   } } この結果が、 400000 :3.063 0 :0.468 0 :0.594 0 :0.766 0 :0.859 0 :1.11 0 :1.187 0 :1.141 0 :1.343 0 :1.469 となり、初回以降 $buffer の長さが0となるのも不可解ですが、funcA の実行時間が増加していくのも理解できません. これを #! /usr/local/bin/perl use strict; my $time0; my $buffer; # 注1 $buffer をファイル内大域変数として宣言 for(my $i=0; $i<10; $i++){   $time0 = times();   &funcA();   print((times() - $time0). "\n"); } sub funcA {   $buffer = ''; # 注2 レキシカル変数宣言をやめた   &funcB(1);   print length($buffer) . " : ";      sub funcB{     my $n = shift;     $buffer .= 'test';     return if($n==100000);     funcB($n+1);   } } とすると、結果は 400004 :3.188 400004 :0.234 [以降、上にほぼ同じ] と文字列長は正しいものの,初回以降のfuncA実行時間が極端に減ります. 内部ではどういうことが起こっているのでしょうか.

    • ベストアンサー
    • Perl
  • サブルーチンの使い方

    以下のプログラムを解読中ですが、いまいち理解できません。C言語の経験はあるのですが、Perl初心者のため、Perlの文法を中心に、以下のポイントについて教えてください。 (1)この関数で、引数が「&@」となっていますが、この&の意味は「サブルーチン」ということですか?? (2)2行目のmy ($block, @listin) = @_ で各$block, @listinに格納される値を教えてください。「@_」を調べてみたところ、「サブルーチンの引数を代入」とあるのですが、ここでは、map_block(&@)の&@が&blockと@litinに代入されるということですか??そもそも&@とは何でしょうか? (3)4行目のpush @listout, &$block() for (@listin) について、push関数を調べてみたところ、配列の最後尾に値を格納するということですが、&$block() for (@listin) の部分の意味がよくわかりません。どのような値が、配列listoutに格納されるのでしょうか? (解読中のプログラム) 1sub map_block (&@) { 2   my ($block, @listin) = @_; 3 my @listout = (); 4 push @listout, &$block() for (@listin); 5 return @listout; 6}

    • ベストアンサー
    • Perl
  • サブルーティンの使い方。

    サブルーティンの理解を深めるために、 階乗の計算をサブルーティンで行うプログラムを作りました。 自作のプログラムについて質問を二つしたいと思います。 1.一応、計算は出来るのですが、 定型的でないというか、無駄が多いというか、 何か違う気がするのです。 どこか変なところはありませんでしょうか? 2.エラーメッセージをどこにいれたらいいのかわかりません。 数字以外、(例えば文字)が入力されれば1が出力されるようにはしたのですが、 「これは数字ではありません」のようなエラーメッセージを出したいのです。 この場合はどこにどのように記述すればいいですか? 色々試してみたのですが、思い通りに動きませんでした。 みなさま、知恵をお貸しください。 ------------------------------------------- use strict; print "数字を入力してください。\n"; chomp( my $number = <STDIN> ); my $k_number = kaijo($number); print "入力された数字の階乗は$k_numberです。\n"; sub kaijo { my $number = shift @_; return undef if $number < 0; return 1 if $number == 0; my $kaijo = 1; for(my $i = $number; $i>1; $i--) { $kaijo *= $i; } return $kaijo; }

  • サブルーチンからサブルーチンを呼び出す

    #平均を求める,サブルーチンを使用 @dat=(1,2,3,4,5,6,7,8,9,10); $mean=&mean(@dat); print "mean="; print $mean; sub mean{ $sum=&sum(@dat); $n=@dat; $mean=$sum/$n; return($mean); } sub sum{ for($i=0;$i<$n;$i++){ $sum+=$dat[$i]; } return($sum); } Perlを勉強し始めたのですがサブルーチンの所で分からない所があるので教えていただけませんか? mean関数(Perlではmeanルーチンなどと呼ぶべきでしょうか?)の中でsum関数を呼び出してデータの合計を$sumに代入したいのですが,この場合だとうまく代入されていないようなのですが,何がよろしくないのでしょうか?

    • ベストアンサー
    • Perl
  • perl サブルーチンでのファイル出力結果おかしい

    以下のコードを実行するとカレントディレクトリの配下にある すべてのファイルのリストがコンソールとファイルに出力される はずですが、コンソールに表示されているファイルの一部しか ファイルに出力されていません。 どうも、最後に do_file()を呼び出したときのファイルしか リストされていないようなのですがなぜでしょうか。 どのようにすればよいのでしょうか。 よろしくお願いします。 (Windows7, ActivePerl(v5.16.3)) ----test.pl--------------------------------------------- &do_dir('.'); sub do_dir{  open(FILE2,'>list.txt') or die "$!";  my $dirname=shift;  my $delim='/';  opendir(DIR,$dirname) or die "$!";  foreach $entry (readdir(DIR)){   next if($entry eq '.');   next if($entry eq '..');   if ($dirname=~/[\\\/]$/) {    my $delim='';   }   my $filename="$dirname$delim$entry";   if(-d $filename){    &do_dir($filename);   } else {    &do_file($filename);   }  }  close(DIR);  close(FILE2); } sub do_file{  my $filename=shift;  return unless ($filename=~/\.*$/);  print "$filename\n";  print FILE2 "$filename\n"; }

    • ベストアンサー
    • Perl
  • サブルーチンやif分以外での中括弧

    perlについて学習中で、現在フリーのスクリプトを見て勉強しております。 中括弧の使い方を教えて欲しいです。 sub test { print"OK"; } if ($test>1) { print"OK"; }else{ print"NG";} 上記のようにサブルーチンやif文での使い方は分かるのですが、フリーのスクリプトの中に単に中括弧を使用している部分がありました。 例) { ←この括弧    my(@new);    for(0..3){if($tmp[$_]=~/jpg/){push(@new,$tmp[$_]);}} } 矢印の部分の部分の括弧ですが、これはどのような意味があるのでしょうか? よろしくお願いします。

    • ベストアンサー
    • Perl
  • not enough argument in 3rd line & does not show the right response

    test.datの中身は以下の通り。 line a b c d 1 1a 1b 1c 1d 2 2a 2b 2c 2d 文字と文字の間の空間はタブです。 open (my $SIM_FILE, "test.dat") or die "can't open the file\n"; my @cols = split /\t/, readline($SIM_FILE); my %simulation = &read(@col); close $SIM_FILE; while ((my $key, my $value) = each(%simulation)) { print "$key : $value\n"; } sub read { while (my $line = readline($SIM_FILE)) { chomp $line; next unless ($line); my @values = split /\t/, $line; if (@values == @cols) { my %tmp_hash; my $year for (my $i = 0; $i<@cols; $i++) { $tmp_hash{$cols[$i]} = $values[$i]; $year = $values[$i] if ($col[$i] =~ /^year$/i); } $simulation{$year} = \%tmp_hash; } } }

    • ベストアンサー
    • Perl
  • リファレンスをサブルーチンの戻り値にしてもOKですか?

    ■ サブルーチン内部で処理した結果を格納した、配列、ハッシュ、スカラーなどのデータを戻り値として利用する必要があります。その場合、どうするのが標準的なやり方でしょうか? ■ return (配列へのリファレンス, ハッシュへのリファレンス, スカラー); などとやってしまっても問題はないでしょうか? ■ 下のプログラムを試したところ、予想に反しちゃんと 「31415」と表示されました。 #!/usr/bin/perl -w sub subroutine{ my @a = (3, 1, 4, 1, 5); return \@a; } my $b = subroutine{}; print @$b; ■ サブルーチン内部で使用した変数へのリファレンスをサブルーチン 外で使っていいのだろうか? サブルーチンの処理が終了した時点でサブルーチン内部で使用した 変数はメモリーから消去されるのかと思ったものですから。

    • ベストアンサー
    • Perl

専門家に質問してみよう