- ベストアンサー
プログラム1行ずつみていったところ、何をしているか分からないところがけっこうありまして。。。[Perl初心者]
- プログラム1行ずつみていったところ、何をしているか分からないところがけっこうありまして。
- Perl初心者で困惑しております(><)以下の文でコメントがないところ分かりません。 コメントあるところも怪しいかもしれません。
- プログラムの詳細な内容を把握するのは難しいですが、ループと条件分岐が使われていることがわかります。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
> $a =~ s/\n$//; で$aの末尾の末尾の改行文字(\n)を捨て、 > @b = split(/,/,$a); で$aを'を区切り文字として分割し、分割した各要素を配列@bに入れています。 ここの動作はsplit関数について調べて、実際に使ってみればすぐに分かります。 http://www.rfs.jp/sb/perl/05/split.html 残りは#1で説明した内容とほとんど同じです。 なお、こういう処理(セパレータで文字列を分割)をする場合はsplitを使うのが普通です。 最初のプログラムの方はどちらかというと変わった書き方ですね。
その他の回答 (1)
- Werner
- ベストアンサー率53% (395/735)
まずこのプログラムは1つのプログラムではありませんね? 私が見た限りでは > while( $a = <> ) 以降は別のプログラムであるのが自然だと思いましたが。 また、それぞれのプログラムがそもそもどんな処理をするためのものかは分かっているのですか? (こういう情報は、分かっているのなら回答者の理解を助けるためにも質問時に書いておくべきです。) ソースコードを読んでみましたが、 1つめのプログラムは CSV(Comma Separated Values)を出力するプログラムのようです。 CSVは名前の通り各値を,(カンマ)で区切って並べたものです。 2つめのプログラムは 1つめのプログラムで生成されたCSVを読み込んで 行と列それぞれの平均値を出力するようです。 私なりにコメントを追加・変更したコードを下に示します。 コメントで書ききれなかった分は一番下に書きました。 --------<1つめのプログラム>-------- #79行21列のCSVを出力 #ただし一列目は行の名前 #各値は20以上100未満の整数、または空である for($i=1; $i<80; $i++) { #$iが80未満の間ループ、$iは初期値1で1ずつ増える。ループ回数79回 printf("a2006%03d",$i); #a2006001から2006079まで出力。 for($k=0; $k<20; $k++) { #20回ループ $pnt=int(rand(100)); #0以上100未満の整数乱数をpntに代入。 print ","; #,を出力。 if( $pnt >=20 ) { #pntが20以上ならpntを出力。 print $pnt; } } print "\n"; #改行を出力。 } --------<2つめのプログラム>-------- #標準入力からCSVを読み込み #各行や各列の値の平均値を求める #ただし平均値を求めるに当たって空の値は無視する while( $a = <> ) { #標準入力から1行ずつ読み込んで$aに代入 $a =~ s/\n$//; #$aの末尾の改行コード(\n)を捨てる。 @b = $a =~ /^([^,]*)(,*.*)$/; #$aの最初の,(カンマ)より前を$b[0]に、残りを$b[1]にいれる $name = $b[0]; $seq =0; $isum = 0; $icnt =0; while( $b[1] ne "" ) { #処理中の行を全部処理し終わるまでループ @b = $b[1] =~ /^,([^,]*)(,*.*)$/; #$b[1]の最初の,は捨て、次の,より手前の部分を$b[0]に移す if( $b[0] ne "" ) { #空の値は無視する $isum += $b[0]; #行の合計値を求めるために値を加算 $sum[$seq] += $b[0]; #列の合計値を求めるために値を加算 $icnt++; #行中の空でない値(数値)の数をカウント $cnt[$seq]++; #列中の空でない値(数値)の数をカウント } $seq++; #,(カンマ)の数、すなわち空も含んだ要素の数をカウント } printf("%s:%.2f\n", $name, $isum/$icnt); #行の名前とその平均値を出力 } for($i=0; $i<=$#sum; $i++) { #配列@sumの配列要素数分(=列数)ループ #各列の平均値を出力 printf(" %.2f", $sum[$i]/$cnt[$i]); } print "\n"; --------<End>-------- > $a = <> この部分は厳密には「標準入力から入力が与えられた場合はそちらを読み込み、 ファイル名が引数として与えられた場合はファイルから読み込み」ます。 http://infosys.gsid.nagoya-u.ac.jp/~ohna/perl_lesson/perl04.html > @b = $a =~ /^([^,]*)(,*.*)$/; この部分では、 $a =~ /^([^,]*)(,*.*)$/ でマッチングが行われ、 パターンの中のカッコで括られた部分に対応した要素を 配列として@bに代入しています。 例えば、$a="1,2,3,4,5,6"だったなら、 /[^,]*/は"1"にマッチし、/,*.*/は",2,3,4,5,6"にマッチするので、 この処理の結果@b=("1", ",2,3,4,5,6")となります。 http://www.rfs.jp/sb/perl/02/09.html 詳しくはこのページの 「リストコンテキストでのパターンマッチ」を参照してください。 (正規表現やパターンマッチ自体を知らないなら全部に目を通した方がよいでしょう。) #余談 質問者さんの元のコメントを見て、 forループの挙動がよく分かっていない、 パターンマッチについて知らないという印象を受けました。 Perl初心者ということですが、 分からないところの方が多いような状態なら 先にPerlの基本的なところを一通り勉強をしておくことを勧めます。
お礼
丁寧に教えていただき本当に有り難うございました。じつはお礼を載せたつもりでしたが、コンピュータが重かったので載らなかったようです。お礼が遅れてしまい申し訳ありません。。(><) ちなみに以下のプログラムでも同じ結果がでるようですが、この場合はどういった感じに見ていけばいいのでしょうか。。。 while( $a = <> ) { $a =~ s/\n$//; @b = split(/,/,$a); $isum=0; $icnt=0; for($i=1; $i<=$#b; $i++) { if( $b[$i] ne "" ) { $isum += $b[$i]; $sum[$i] += $b[$i]; $icnt++; $cnt[$i]++; } } printf("%s:%.2f\n", $b[0], $isum/$icnt); } for($i=1; $i<=$#sum; $i++) { printf(" %.2f", $sum[$i]/$cnt[$i]); } print "\n";