- ベストアンサー
perl初心者ですが、プログラム作成で行き詰ってしまいました。
perl初心者ですが、プログラム作成で行き詰ってしまいました。 参考書を読みあさり、色々とググってみたのですが、どうしても組み立てられません。知識のある方ご回答よろしくお願いします。 一つ目は: 英語の文章を記憶したファイルを指定し,その内容を読み込み,文章内に含まれる単語を出現頻度の降順で表示させるプログラムを作成すること 「1位:・・・(・・回)」 「2位:・・・(・・回)」 ... なお,一つの単語が二行にまたがることはないものとする。 二つ目は: テストの成績データを記憶したCSV ファイルを指定し,その内容を読み込み,各学生の総合点と順位,各科目の最高点,最低点,平均点を記憶したCSVファイルを書き出すプログラムを作成せよ。 なお,入力用のファイルと出力用のファイルはキーボード入力で指定するものとする。 また,異なる学生数および科目数のCSV ファイルを読み込んでも正しく動作するようにすること。 卒業のかかったレポートで、この二つを完成させないと先に進めないのです。 本当に図々しい質問で大変申し訳ありません。知識のある方どうかご教授ねがいます。 *ひとつめに関しては: open (FILE, 'perl.txt') or die "$!"; while (my @array = <FILE>){ foreach (@array) { $count{ $_ }++ ; } @rank = sort { $count{ $b } <=> $count{ $a } } keys %count ; foreach (0..$#rank) { $kagi = $rank[ $_ ]; $kaisu = $count{ $kagi } ; print $_+1, "位:$kagi($kaisu 回)\n" ; } } のように書いたところで行き詰ってしまいました。 二つ目は: open (FILE, 'data.txt') chomp(@data = <FILE>) ; $i= 1 ; # 行番号を記憶する変数 for (@data) { # 各行に対して以下を繰り返す. # 各行の数値を配列の要素として記憶する. @list = split(/,/, $_) ; # サブルーチンを呼び出して,結果を表示 print "$i行目:" ; print "数値:",&cardinality(@list),"個," ; print "最大値:",&maximum(@list),"," ; print "最少値:",&minimum(@list),"," ; print "合計:",&summation(@list),"," ; print "平均:",&average(@list),"\n" ; # 行番号の更新 $i++ ; } とまで書き、もう何が何だか訳わからなくなってしまいました。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
こんにちは。 Perlがどうのというよりまず、プログラムというものをどのように動かすのかが整理出来ていないように思われます。 コレはどんなプログラム言語を使うにしても同じです。なぜなら、結果的に命令を受けるのは同じコンピューターだからです。 1.何をさせたいのかを整理する。 ・英文から単語を抽出したい ・単語の出現頻度をカウントしたい ・それを多い順に並べたい ・それを画面に出力したい 実現するには、上の大まかなプロセスが必要だと分かってくるはずです。 これが分かってしまえば、後はそれら一つ一つを別のプログラムと思ってスクリプトの手順を考えてみます。 2.何をしたらいいのか考える 何をさせたいのか、から「何をしたらいいのか」に変わります。ここがポイント。 コンピューターに分かるように話すには、どうやって言えばその通りにしてくれるのか…というステップ。そしてそれは今回、「Perlという言葉で話す」という条件が初めて適応されるシーンです。 まず、最初の英文から単語を抽出する所を考えてみましょう。 ・英文を渡す ・単語で区切る ・区切ったそれを個々の物として分類したままの状態にさせる 英文を渡すのはファイルを開いて入力すればよい、というのがすぐに分かりますね。 では、次に英語を読めない(というか、文字という概念すらない)コンピューターに単語を理解してもらうにはどうすればいいでしょうか。 英文の特徴を見極めて、人がその橋渡しをしてあげるしかありません。 特徴は、先に書かれた御方の仰るとおり、単語と単語の間に必ずスペースがある事です。 (多分、課題を英文に限定されたのは、ここの所に気が付いて欲しかったのだと思いますが…) させたい事がはっきりとしない段階では、マニュアル本はあまり意味がありません。こういったプロセスを経て初めて、「コレが出来そうな関数はどれかな?」と調べる事ができます。 関数の説明には、表だった使い方や使用目的が書いてあると思います。 しかし、説明されている使用目的と違っていても、自分のやりたい事に転用出来そうならばそれを使ってみて構わないのです。 関数の説明の、文字で書かれた用途を見るよりも、それがどんな動きをするものなのか、動作の本質を見てください。 プログラムを書くに当たって、一番大事な事は、させなげばならないプロセスをはっきりと認識する事です。 認識してしまえば、それらはとても小さくて簡単なプログラムの集合体だと気が付くはずです。 ある程度の関数の知識があればより考えやすくなりますが、ここまでのプロセスにはプログラムの言語の知識はあまり必要がないです。 いきなり書き始める前に、完成図をしっかりとイメージし、プロセスを考えてみてください。 スクリプトを詳しく書いて答えを開示する事も出来ますが、それはあなたの課題なのであなたの書き方で答えを導いてください。 こういう風にプロセスを分解すれば、全然難しくない課題ですから。 特にPerlは様々な書き方でそれを実現させる事が出来る言語ですしね。 ここでネタばらしをもらってしまっては、多分ずっと自力でスクリプトを扱うのはムズカシイと思います。 がんばって!!!
その他の回答 (2)
- ORUKA1951
- ベストアンサー率45% (5062/11036)
行き詰まりが早すぎます。(^^) 基本ですが、 1) フローチャートをまず書いてみること 2) 一つ一つのプロセスについて作っていくこと サブルーチンごとに製作していくこと 3) 各段階での入出力値を確認してバグを取り除く 4) 全体を組み立ててバグをつぶすこと 1について 配列にいきなり入れないほうが良い。 英文は単語境界が空白文字なので空白文字で区切って、単語ごとにハッシュをつくり、ハッシュの値は登場数とする。(大文字小文字を区別しない) これを文章の最後まで行う。 ハッシュの値でソートする。 2について CSVファイルを配列のハッシュに格納する。 同時に、各科目の最高点,最低点のハッシュや平均点を計算する。 CSVに変換する。 ★CSVは、それを作成するソフトによってフォーマットが異なります。MS office Excellは独特です。 なお、文字列の取り出しや正規表現については下記サイトに良い情報がたくさんあります。 【参考サイト】 Perlメモ http://www.din.or.jp/~ohzaki/perl.htm
お礼
回答ありがとうございます。 具体的なアドバイスを元に、フローチャートを書き、各プロセスを整理して書き直しました。 丁寧なアドバイスをいただき、本当にありがとうございます。
- Tacosan
- ベストアンサー率23% (3656/15482)
上の方でいうと, 「行き詰った」というからには目的とする動作と現在のプログラムの動作で食い違いがあることは認識できていて, でもその食い違いをなくすためにどう修正すればいいかが分からないってことだよね. どう食い違っているのか説明できますか? 次: 何がどう「訳わからない」のか説明できないと, こっちもどういっていいのかわからない. とりあえず全部一度にやろうとするんじゃなくって, どれか 1つでいいから動くように作ってみてください. いくつかサブルーチンを呼び出してるけど, それらは書けますか?
お礼
テンパっていて、うまく質問することができませんでした。 落ち着いて整理しなおし、他の方のアドバイスと友人の手伝いもあって、なんとか完成することができました。 ありがとうございます。お世話になりました^^
補足
一つ目に関しては、文章内の単語を表示させたいのですが、このまま実行しても単語ではなく文章(sentence/paragraph)を表示してしまいます。どこがどう食い違っているのかは自分にはまだわからないのですが、ちゃんと“単語”を指定し、表示させるにはどこが間違っており、修正すべきなのかが分からずにいます。 二つ目に関しては、サブルーチンは以下のように書いてます。 #@_ の要素数を返すサブルーチン sub cardinality {$number = @_ ; } # @_ の要素の最大値を返すサブルーチン sub maximum { my $max = shift @_; for (@_) { $max = $_ if $max < $_ ; }$max ; } # @_ の要素の最少値を返すサブルーチン sub minimum { my $min = shift @_; for (@_) { $min = $_ if $min > $_ ; } $min ; } # @_ の要素の合計を返すサブルーチン sub summation { my $sum ; $sum += $_ for @_ ; $sum ; } # @_ の要素の平均を返すサブルーチン sub average { &summation(@_)/&cardinality(@_) ; }
お礼
わざわざありがとうございます。 改めて各プロセスを見直し、友人の手伝いもあって、なんとか完成させることができました。 丁寧なアドバイス、本当にありがとうございました。