[目次] [第2回] [第4回]

Ruby勉強会(第3回)

練習2-3の回答例

練習2-3の回答例のプログラムの全貌は はex2-3-2.rb〜ex2-3-4.rbとしておいておく。

1.については、プログラムを実行するだけなので説明を省略する。 2.は文字列を連結するので、最初に1文字も文字が入ってない文字列 (空文字列)を準備しておき、それに「+」で連結していけば良い。 空文字列は「""」と記述する。もし、改行文字「 "\n"」 を削除したい場合は、メソッド「chomp」を入力文字列に 適用すると、削除した結果を得ることができる(ex2-3-2a.rb)。

3.については、入力した文字列を整数値に変換するメソッドを用いて、 その結果を足していく。もちろん積算する変数には初期値として0を入れておく 必要がある。

4.は入力文字列を引数としてメソッド「eval」を呼び出し、 その結果をメソッド「p」で表示すれば良い。なお、ex2-3-4.rbでは 終了条件をそれっぽく「exit」に変えている。

例外処理

前回の練習2-3の3.のプログラムの応用例を考えてみる。単に積算するの ではなく、何件のデータを積算したのか、そしてその平均値はいくらかを 計算するものとしてみたプログラムが次のex3-1.rbである(行番号は説明の ためにつけているもので、プログラムの一部ではない。)

     1  sum = 0
     2  i = 0
     3  while true
     4      line = STDIN.readline
     5      if line =~ /end/
     6          break
     7      end
     8      sum = sum + line.to_i
     9      i = i + 1
    10  end 
    11  p(sum, i, sum.to_f / i)

11行目のように複数の引数を指定するとメソッドpは それぞれの引数を画面に表示する。なお、平均値の計算の際は、そのままだと 整数で計算するため、小数部が得られないので、メソッド「to_f」を 用いて実数(浮動小数点数)に変換してから計算している。

このようなデータを入力して処理する場合、キーボードから一々入力 するのではなく、データをファイルに格納しておき、そのファイルからデータを 読み込みながら処理するのが一般的である。このプログラムのままでもUnix/Windows のリダイレクトの機能を用いて(データが入っているファイルを「 d1.txt」 と仮定する)、
ruby ex3-1.rb < d1.txt
のように「<」で標準入力をキーボードではなく、ファイルに 切替えることができる。

Rubyでは、このような使い方をもっと簡単に、そして複数のファイルから 入力できるようにする機能がある。上の4行目を
line = readline
に書換えたプログラムを仮にex3-1a.rbとすると、
ruby ex3-1a.rb
とのみ実行すればキーボードから、
ruby ex3-1a.rb d1.txt
とすれば、d1.txtから、
ruby ex3-1a.rb d1.txt d2.txt … dn.txt
とすれば、d1.txt, d2.txt, … dn.txtのファイルから順に 読み込んでいく。

さて、このようにファイルから入力するようになると「データの終り」に ついて少し考える必要が出てくる。これまではデータの終りを表すために 「end」と最後に入力する約束にしていた。これを一々指定するのは 面倒であり、上記のように複数のファイルを対象にすると、そのうち最後の ファイルの最終行にのみ入れておかないと、途中のファイルに「 end」 という行があると、その時点で処理が終り、残りのデータを無視することに なってしまう。一方、データのファイルに「end」を入れ忘れると、 データを最後まで読み込んだ後に、 「ex3-1a.rb:4:in `readline': End of file reached (EOFError) from ex3-1a.rb:4」のようなメッセージを表示して、処理を中断してしまう。

このメッセージは「ファイルの終りに達した(EOF - End Of File)」という 処理上の「例外」が発生したので、そこで処理を中断したことを表している。 「例外」が発生すると、本来の処理をそのまま続けることができないので、 Rubyでは特に何も指定してない時は発生した例外に関するメッセージを表示 して、実行を終了(中断)するようになっている。

一方、この例外が発生した際に処理を中断せずに、その例外を 回避するための処理を行った上で、処理を継続させることも可能である。 このことを「例外処理」と呼ぶ。例外処理についてはrubyman.pdfの p.63付近に説明があるが、一般に以下のように記述する。 (実際にはもう少し柔軟な記述もできるがここでは典型例のみしめす。)

begin
    例外が発生するかもしれない文
rescue [例外のクラスの並び] [=> 例外を表すオブジェクトを格納する変数名]
    例外発生時に処理すべき文
end

ここでrescueの前の文で例外が発生するとその例外が指定した クラスに属するものであれば、それを表すオブジェクトを変数に格納して rescueendの間の文を実行する。なお、クラスの並びを 省略すると全ての例外を対象とする。また、オブジェクトを受け取る必要が なければ、変数も省略可能である。

練習3-1

  1. ex3-1a.rbを完成させ、複数のファイルをnotepadなどで準備して、 実際にファイルから読み込んで集計するプログラムとして動くように してみよ。その際、end を書かなければEOF 例外が発生することも 確認すること。
  2. 最後に結果を表示するところはメソッドpのままでは見にくい。 C言語と同じようにprintfを使用することができるので、 それで表示部分を見やすくしてみよ。(書き方はほとんど変わらない)
  3. 上で説明した例外処理の記述を用いて、データのファイル中に 「end」と書かなくても正常に実行をし、結果を表示するように 修正してみよ。

[目次] [第2回] [第4回]

by Tetsuo Sakaguchi
2007年 1月12日 金曜日 15時06分00秒 JST