今年は天候不順なのかなかなか日差しを見る機会が少ないですね。平日は職場にいるので、通勤以外では天候はあまり関係ないのですが、休日だけでも晴れて欲しいです。
14 号では寄り道をしてエラーの修正方法について説明しました。掲示板作りには直接関係しませんが、今後自分で CGI プログラムを作る時に役立つと思うので、参考にして下さい。
今号からは 12 号で作った簡易掲示板に改良を加えていきます。 簡易掲示板には機能不足な点が幾つかありますので、それを解消していきましょう。 まずは表示に関連する部分から変更を加えていきます。
この記事は以下のような人を対象としています。
この連載は前号までの記事を読んでいる方を対象として書かれています。 今号を読む前に前号までの内容を把握しておいて下さい。
必要なものは下の 2 つです。
この他に RDE を使います。これらの準備の方法は 11 号 で述べたので、 詳しくはそちらを参照して下さい。 今号で使うプログラムを zip ファイルにまとめてあります。 前号と同じようにダウンロードして C:\ に展開して下さい。 rubima015-cgi.zip
今回もまずは Ruby の機能を紹介していきます。 例によって 14 号で紹介した機能を使いますので、 不安な方は復習しておいて下さい。
プログラムを書いていると同じようなことを繰り返したいことがあります。 例えば、Array の中身をすべて表示させる時。 今までなら print 文を何回も書いて Array の中身を表示させていました。 具体的には下のようなプログラムです。
Array の中身が少ない時はこのように書くことも可能ですが、 Array の中身が 100 個や 1000 個になると、 上記のような方法は現実的ではありません。
このような時のために Ruby には繰り返しの機能があります。 繰り返しを使うことでプログラムを簡潔に書くことが出来ます。 繰り返しの方法はいくつかありますが、 この連載では主に while 文を使います。
while 文は下のように使います。
(条件) が真である時に (繰り返したいこと) の部分が実行され続けます。 上の print だらけのプログラムを while 文を使って書き直してみましょう。
プログラムは少し長くなっていますが、 このように書くことで Array の中身が 1000 個になっても対応可能です。
まず 変数 a, m, i の役割を説明しましょう。 それぞれの役割は下の表のようになります。
変数 | 役割 |
a | Array を指す |
m | Array の中身の個数 |
i | print で表示させる Array の添字 |
一番のポイントは変数 i です。 もし、変数 i の値が 0 であれば、 print では添字 0 が指す Array のデータ (Array の最初のデータ) を表示させます。 同様に変数 i が 1 であれば Array の 2 番目のデータが表示され、 2 であれば 3 番目のデータが表示されます。 これでわかるように、一般的に、Array の (1 から数えて) n 番目の中 身を表す添字は、n ではなくて n - 1 です。
変数 m は Array の中身の個数を表し、 while 文の (条件) で使われます。 (条件) では変数 i が添字の範囲を超えていないかをチェックしています。 添字の最大数は Array の中身の数より 1 小さいので、 添字の範囲は 0 以上、変数 m 未満となります。 このことを利用して while 文の (条件) では 変数 i が添字の範囲を超えていないかどうかを調べるのです。
では、プログラムの説明に移りましょう。 1-3 行目は各変数への代入を行っています。 4-7 行目が while 文です。
4 行目の while の後ろの i < m が while 文の条件になります。 この i < m は変数 i が変数 m より小さいという意味です。 変数 i が変数 m の値以上になるということは 添字の範囲を超えることを意味します。 これ以上繰り返し必要はありませんので、 while 文を使った繰り返しを終了させるために i < m という条件としています。 5 行目では変数 i に対応する添字のデータを表示させます。 6 行目は少し不思議に思うかもしれません。 通常、数学ではこのような式は見かけないと思います。 この行の意味は 6 行目を実行する前の変数 i の値に 1 を足し、 変数 i に代入し直す ということです。 この行がないと、while 文の繰り返し部分を何回実行しても添字が増加しないので、 プログラムが終了しないことになります。
もう一度 while 文の部分を順に解釈し直してみましょう。
6 行目で 変数 i は 1 となります。
6 行目で変数 i は 2 となります。
6 行目で変数 i は 3 となります。
もう一つ別の例を見てみましょう。 下のプログラムは Array の中身をすべて足していくプログラムです。
最初の 4 行は準備です。変数 a が Array、変数 i が添字となる数字、 変数 m が Array の中身の個数、変数 sum が合計の数に相当します。 変数 sum は最初 0 から始まり、while 文の繰り返しの部分で数字を足していきます。
5-8 行目が while 文です。 while 文の条件の部分では先ほどと同じく変数 i が Array の添字の範囲にあるかをチェックしています。 繰り返しの部分の 6 行目では変数 sum に Array の中身の数が足されています。 この行が繰り返されることでArrayの中身のすべてが足されます。
繰り返しの部分は難しいと思うので、少しずつ見直してみましょう。 まず 4 行目が終わった時点での各変数についてチェックします。 それぞれ下の表のようになります。
変数 | 値 |
a | [1,3,5,7,9] |
m | 5 |
i | 0 |
sum | 0 |
次に繰り返しの部分について考えてみましょう。 1 回目の繰り返しの部分の処理は下記のようになります。
以後は同じような処理が続いていきます。 変数の変化だけを下の表に載せます。 それぞれの変数の値は繰り返しが終わった後の値です。 例えば、3 回目の繰り返しが終わった段階、つまり、 7 行目を 3 回実行した後では 変数 m は 5、変数 i は 3、変数 sum は 9 になっています。
繰り返しの回数 | 1 | 2 | 3 | 4 | 5 |
m | 5 | 5 | 5 | 5 | 5 |
i | 1 | 2 | 3 | 4 | 5 |
sum | 1 | 4 | 9 | 16 | 25 |
繰り返しが 5 回終了すると、次に 6 回目の条件チェックに入ります。 この時 i < m は成り立ちません。 変数 i, m ともに 5 なので、i < m とはならないからです。 この時点で while 文の条件を満たさなくなるため 繰り返しは終了し、次に 8 行目が実行されます。 8 行目では変数 m の値である 25 を表示して、 プログラムは終了します。
12号 の each の説明 で紹介したように Array には each というメソッドがあります。 これを利用すると、while 文よりも間単に Array の中身を順番に処理することが出来ます。
arr.each と end の間に繰り返したいことを書きます。 この場合は「p i」が相当します。 「do |i|」というのは each のようなメソッドに特有の書式で、 メソッドによって色々な意味があるのですが、 each の場合には今繰り返している Array の中身が 変数 i に代入されます。 上の場合ならば、変数 i に順番に 1,3,5 が代入されて、 その都度に繰り返し部分の「p i」が実行されます。
処理を順番に見ていくと、下記のようになります。
上から分かるように繰り返しの終了の判定は each メソッドがしてくれます。 while だと最後の添字かどうかを自分でチェックしなければならかったのですが、 その部分を each が処理してくれます。 each を使う方が while よりも楽に書けますね。
ここでは Array の内容を逆順に表示させます。 例えば、[1,3,5]というArrayであれば
と表示させることになります。
下に while を使ったプログラムを示します。 基本は先ほどと同じですが、 条件チェックや添字の変化のさせ方が異なっています。
まず添字にあたる変数 i が最後の添字から始まることが大きく違う点です。 最後の添字は Array の中身の数より 1 小さいので注意して下さい。 しばしば 1 小さいことを忘れてしまいます。
次の変更部分は繰り返しの中で変数 i の値を 1 ずつ減らしている点です。 これによって添字は繰り返しごとに 1 ずつ減っていくので、 Array の中身を逆順に表示することになります。
最後の大きな変更点は添字の範囲のチェックが 0 以上になっていることです。 while の条件部分で使用している「>=」は「以上」を表す記号です。 このチェックがないと添字がどんどんと減っていって 添字の範囲から外れても繰り返しが終了しません。
each の仲間に reverse_each というメソッドがあります。 reverse が逆を意味することから分かるように、このメソッドを使うと、 Array の中身を逆順に繰り返す事が出来ます。
使い方は each と同じです。このような例であれば each を reverse_each に変更するだけです。
Ruby には true、false、nil という値 (これもオブジェクトです) が存在します。true や false は真や偽を表す値で、nil は何ものでもないということを表す値です。ここではこの 3 つについて説明します。
最初は nil からです。
nil は 何ものでも無いということを表すオブジェクト のことです。 禅問答のように聞こえるかもしれませんが、 とりあえずそういうオブジェクトと思っておきましょう。
nil が出てくる場面はいくつかありますが、 1 つの例として添字の範囲を超えて Array の中身を使おうとした時に出現します。
上のプログラムの 4 行目では Array の 3 番目の値を 表示させようとしていますが、 Array には 2 個しかデータがありません。 そのため 4 行目では nil が表示されます。 このような時に 「何ものでも無いオブジェクト」である nil が利用されます。
次に true、false という値について説明しましょう。 これらは条件を評価した時の真偽を表すオブジェクトです。 真を表す値は true、偽を表す値は false になります。
例えば、下のプログラムを RDE で実行してみて下さい。 それぞれ、true、false と表示されます。
Ruby が 1>0 や 0>1 といった条件を評価して true や false という結果を出しています。
while 文や if 文の条件は Ruby によって評価されて、 true、もしくは、false となります。
例えば、下のプログラムなら 10 > i が 評価されて true か false のいずれかになります。 変数 i の値が 9 以下であれば、 条件は true と評価されて while 文の繰り返し部分が実行され、 10 以上であれば false と評価されて繰り返しが中止されます。
if 文や while 文で直接 true や false を使うことは少ないと思います。
例えば、下のように条件部分に true を使うと、 while 文の繰り返しが続くので、 終了しないプログラムを作ることが出来ます。 皆さんは強制的にプログラムを終了させる方法を知らないので、絶対に実行しないで下さい。
逆に全くwhie 文の繰り返し部分を実行しないプログラムも作ることが出来ます。 下の例では条件部分が false であるため繰り返し部分は 実行されずに終了してしまいます。
前者に関しては時々使うこともありますが、 後者に関してはほとんど使うことはありません。 両者とも CGI プログラムでは使う頻度はあまり高くありません。
Ruby では変数の値も while 文や if 文の条件になることが出来ます。 この場合、false と nil 以外はすべて真として扱われます。
false、nil 以外は真として扱われるので、 上に示した終わらないプログラムの条件部分を文字列で代用することが出来ます。 その例を下に示します。 “123” は false でも nil でも無いので、 真として扱われて while 文が終了しません。
false と nil が 偽、それ以外が真 として扱われることを覚えておいて下さい。