- 本日の作業内容
- 現況報告
- 小テストの状況
専用のページを用意していますので,解答例を参考に自分の状況を把握してくだ
さい.評価分布の図もありますので,相対的な位置の把握もできればお願いしま
す.なお,個別の成績についてはメールでの問い合わせには応じるようにします.
- 最近良く見る間違い
- printf 文の二重引用符の後のカンマ抜け
printf "hogehoge %d hogehoge.\n" x
のような間違いが多くなっています.エラーが出ますので実行すれば分かるはず
です.
- スクリプトとテキスト表現の混乱
ワープロやHTML文書ではべき乗のように文字が上付きになる場合に,
x2のように表現できますが,ターミナルでのテキスト
表現では実現できません.その際に,一般的な表現のひとつとして
x^2 というような方法を使います.下付きであれば x_1 の
ように表現することもあります.ところが,Rubyの表現ではべき乗は
x**2 のようになります.両者の混同が多く見られています.
- 数値の型
整数型と実数型で割算には大きな違いが出ます.この区別を忘れて値がおかしく
なるスクリプトも多く見られるようになりました.一般的に計算機言語では,
1 / 2 は0です.注意しましょう.
- 複数行にまたがる文
間違いとは言えませんが,スクリプトにおいても1行の長さをあまり長く取らな
いようにしましょう.エディタの自動折り返し機能が働いた場合には長過ぎると
思って区切るようにしましょう.すなわち,式が長くなれば部分的に変数に置き
換えて長さを短くすることが可能ですし,出力文が長い場合には,複数に分けま
しょう.例えば,
printf "(x, y, z) = (%d, %d, %d) changes into", x, y, z
printf " (r, theta, phi) = (%1.2f, %1.2f, %1.2f).\n", r, theta, phi
|
のように,1行で表示する結果でも,スクリプト上では分けることが可能です.
- Emacsのススメ
gEditという簡単で便利なテキストエディタがあるために,これまではそれを利
用することを前提にしていましたが,制御構造が入ってくると,それらの構文関
係を色分けして表示(図1)してくれる機能を持つEmacsが役に立ちます.興味のある人
は,使いはじめてみて下さい.
図1 RubyスクリプトをEmacsのRubyモードを利用して表示した例
まず,最初に設定が必要です.次のような操作を
行って下さい.
$ mkdir -p ~/lib/emacs
$ cp /usr/share/emacs/site-lisp/ruby-mode/ruby-mode.el ~/lib/emacs
ブラウザの表示幅によって,2番目のコマンドが2行に見えることがあるかも知れ
ませんが,コマンドなのでこれは1行で入力します.改行が入ったままターミナ
ルに張り付けるとエラーになりますので,注意してください.
次が設定ファイルの記述です.gEditでも構いませんので,ホームディレクトリ
にある .emacs.el というファイルの最後に以下の項目を追加して下さ
い.
(setq load-path (append '("~/lib/emacs") load-path))
(require 'font-lock)
(autoload 'ruby-mode "ruby-mode")
(setq auto-mode-alist
(append (list (cons "\\.rb$" 'ruby-mode)) auto-mode-alist))
(setq interpreter-mode-alist
(append '(("ruby" . ruby-mode)) interpreter-mode-alist))
|
間違いを防ぐために内容を自分で打たないでペーストするようにして下さい.こ
こまで完了したならば,Emacsを起動して何かのRubyスクリプト (拡張子が
.rb ) を開いて下さい.自動的にモードが変わってくれます.モードライ
ンにRubyの字が見えたら無事に設定完了です.以後の作業は別ページを参考にし
てください.
- 制御構造 (条件分岐)
前回までのスクリプトは値を代入して計算を行ったり,結果を表示するだけのも
のでした.処理は一番上の行にある内容から順に行われていました.これだけで
全てのことが行えれば楽ですが,実際の処理ではより複雑なことが要求されます.
そして,スクリプトは場合分けや繰り返しを行う必要に迫られて,要求に適した
処理を選んで実行しなければならなくなります.このように,プログラムの流れ
が一連の直線的な動作だけではできなくなって,枝わかれや繰り返しを行うことを
「制御構造」と言います.今週からは,制御構造の基本について学習していくこ
とにします.
プログラミングとは,起りうるすべての場合を想定して,それぞれのケースに対
して処理を用意しておくことです.それは,人に買い物を頼む場合に似てい
るかも知れません.たとえば,自動販売機で飲み物を買ってもらうとします.その場
合に想定するのは,次のようなことでしょうか.
- コーラがあればそれを買う
- コーラがなければスポーツドリンクにする
- スポーツドリンクもなければ冷たい緑茶にする
- 冷たい緑茶もなければ冷たいウーロン茶にする
- それもなければ,1ブロック先の自販機に行って上の作業を繰り返
す.
他にも,自販機や飲料水のメーカを指定する場合があるかも知れませんが,とりあえず,
上のようなことが当然考えられます.ここで,重要なことは,あらかじめ想定さ
れる場合を漏れなくあげることと,必要に応じて処理を繰り返すことです.
このような流れを図1のように記述することも良く行われます.このような図を
「フローチャート」と言います.
図1 自販機でのお使いの図
コンピュータは全く融通が利かないので,大人に依頼するようにはいきません.
よく,融通が聞かないことを「子供の使い」と言いますが,まさしく,そのもの
です.ただし,コンピュータはつかれませんし,だだもこねません.言われたと
おり,黙々と作業を続けます.間違って,いつまでも同じことを繰り返す処理を
つくってしますと,プログラムが終わりません.(このようなものを「無限ルー
プ」と言います.)
そのため,本当に厳密に処理を考えておかないといけないわけです.今回はその中の場合
分けを扱う条件分岐について説明します.
- 真と偽
条件を判断する上で,根拠となるのは「値」が「真」か「偽」かになります.プ
ログラミング言語では,それらをtrueもしくはfalseとして表現しますが,言語
ごとに特徴があって,trueやfalseはそれぞれ「代表値」としてあつかわれます.
Rubyでは,trueとはfalseやnilでは無いという意味になります.nilとは値が
「無い」ことを表す言葉です.たとえば,
としてみましょう.ファイル名をtest.rbとして,これを実行する際に,
$ ruby test.rb 1
のようにすると,結果は,
となるでしょうが,引数をつけないで,
$ ruby test.rb
とすると,結果は,
になるでしょう.ここでは,引数を何もつけないで実行したため,
ARGVには何も値が入っていません.値がないので,出力すると,「値
が無い」と言うことになります.これが,nil です.
さて,以下の実際の例で見ていくことにしま
しょう.
- if
最も基本的な条件判断を行うのが if 文です.「文」とはプログラム
中に記述されている命令で,「式」と呼ぶこともあります.次の例を見てみましょ
う.
a = ARGV[0]
if ARGV[0] then
print "OK\n"
else
print "NG\n"
end
|
このスクリプトのフローチャートは図2のようになります.
図2 コマンドライン引数の有無を判別する流れ
このスクリプトをターミナルで走らせてみます.
$ ruby if.rb
すると,結果は,
となるでしょう.しかし,実行時に引数を何でも良いのでつけてみるとどうでしょ
うか.
if というのは英語の「もしも」ですから,意味はすぐに分かると思い
ます.コマンドライン引数が何らかの値を持てば,すなわち,trueですので,条
件が成立していることになり,OKが表示されます.しかし,値がなければtrueで
はないので,else の方に処理が移ります.else は「それ以
外」の意味ですから,条件が成立しなかった場合の処理をそのあとに記述します.
条件文の最後は end をつけておきます.
処理の文は「字下げ」
をするのが通例です.Rubyでは,字下げは2文字分が推奨されています.そうなっ
ていなくても別に動作に影響はありませんが,他の人に見てもらう場合には,き
ちんと字下げをしておくのがマナーです.Emacsでは,「TAB」キーを使うと正し
い,字下げ位置にカーソルを運んでくれます.
上の例の then は省略可能です.また,else
の処理は無くても良ければ記述しなくても構いません.
上の例のように,if 文は図3に示すような構文になります.
図3 if 文の構造
- 論理演算
上の例は,値が存在するかどうかにより場合分けしましたが,値自体を議論する
ことももちろんあります.つまり,ある数値よりも大きいか,小さいか,という
ような場合わけです.二つの値を比較するときに使用するのが論理演算子で,表
1
のようなものがあります.
表1 論理演算子の例
== | 等しい
|
> | 大きい
|
< | 小さい
|
>= | 以上
|
<= | 以下
|
!= | 等しくない
|
他にも複雑なものがありますが,とりあえず上のものを知っておくと良いでしょ
う.使った例を以下に示します.
a = ARGV[0].to_i
if a > 0
print "positive\n"
else
print "negative or zero\n"
end
|
図4はこのスクリプトのフローチャートです.図2と基本的に同じであることが分かるでしょ
うか.
図4 引数の値の正負を判別する例
値の大小を扱うことが出来るようになると,応用の範囲がぐっと広がります.自
分で次の処理を実行するスクリプトを考えてください.
- コマンドライン引数をひとつ数値として受け取ってxとする
- y = | x | の値を求める
- | x | = hoge のように結果を表示する
|
- 複数の if 文の組み合わせ
最初に紹介した自動販売機のお使いのように,複数の場合分けを実行する必要が
ある場合には,if 文を入れ子にして使うことも可能ですし,
elsif を使うことも可能です.それぞれ,end により
指定する範囲を注意してスクリプトを作成する必要があります.構文を図5に示
します.
図5 if 文の入れ子(a)とelsif 構文(b)
西暦年を
与えた場合にその年が閏年に該当するかどうかの判別を行う流れを図6に示しています.
今度はこれを考えてみてください.結果は一応用意していますが,まずは自分で
考えてみましょう.
図6 西暦から閏年を判定する流れ
実現例 (右クリックで出てくるメニューからダウン
ロード可能)
さらに,複雑な例としては,西暦から元号に直すこともかつて試したことがあり
ます.参考にしてみてください.
- 複数の条件があるときの注意
数学で変数の範囲を決めるときに,
0 < x < 1
のような表現をしました.これは x が0より大きく,かつ,1より小さい,
と言う意味ですが,つい,x が0と1の間,と読みかえてしまいがちです.
その感覚が抜けないと,if 文でも間違いをすることが良くあります.
先ほどの x の範囲の例で行くと,
x = ARGV[0].to_f
if x > 0
if x < 1
str = "in"
else
str = "out of"
end
else
str = "out of"
end
printf "The number is %s the range.\n", str
|
のように二つに分けないと処理できません.これをついうっかり,
x = ARGV[0].to_f
if 0 < x < 1
str = "in"
else
str = "out of"
end
printf "The number is %s the range.\n", str
|
のように記述してしまうと,間違いです.ただし,二つの条件をいちいち分けて
記述するのも面倒なので,論理和や論理積というものも用意されています.上のスクリプ
トは,次のように書くこともできます.
x = ARGV[0].to_f
if x > 0 && x < 1
str = "in"
else
str = "out of"
end
printf "The number is %s the range.\n", str
|
&& の記号が「かつ」を意味します.「または」に相当するの
は,|| です.また,これらは,それぞれ and と or
をそのままスクリプト中に入れても可能ですが,他の言語と共通の記号な
ので,記号の方を覚えておきましょう.
大抵の言語において,これらの演算子は,左側だけで判定が可能な場合には右側
の判定を行いません.そのため,短絡演算子とも言われます.
- 実習作業
この時間に学習したスクリプトを自分で変更を加えたりしながら応用してみて下
さい.
- 小テスト
授業の残り20分くらいでAクラスとBクラス別々の小テストを行いますので,アナウンス
に注意してください.
- 宿題
授業の最後にAクラスとBクラス別々の宿題の案内も出しますので,アナウンスに注意してください.