Ruby TIPS
while修飾子/until修飾子/while文/until文 ― ちょっと便利な繰り返し処理の構文とは?(1)
Rubyに用意されている繰り返し処理構文のうち、while文/until文の基本的な使い方と落とし穴を解説。また、while/until「修飾子」を使った簡潔な記述方法にも言及する。
Rubyでは、while
文やuntil
文などを使った繰り返し処理が記述できる。そういった文による一般的な記述方法だけでなく、while
修飾子やuntil
修飾子を使った簡潔な記述方法も利用できる。今回は、ほかのプログラミング言語にはない、それらの便利な構文の基本的な使い方と、それらを利用した場合の落とし穴について見ていく。
なお、他のプログラミング言語にも一般的に用意されているfor
文も使用できるが、これについては後日公開予定の「TIPS:ちょっと便利な繰り返し処理の構文とは?(for文)」で説明する。
while修飾子やuntil修飾子を利用する
while
文やuntil
文を使った一般的な繰り返し処理の書き方はそれほど複雑ではないので、後掲のコラムにまとめることとして、ここでは、繰り返し処理を簡潔に記述できるwhile
修飾子とuntil
修飾子を紹介する。
これらの修飾子は、繰り返して実行したい式の後ろに書く。
【構文】while/until修飾子を使った「前判断型」の繰り返し処理
式 while|until 条件式
while修飾子では、while
の後の条件式
がtrueを返す間、前に書かれた式
を繰り返し実行する。
一方の、until修飾子では、until
の後の条件式
がfalseを返す間(つまり、trueになるまで)、前に書かれた式
を繰り返し実行する。
簡単な例で見てみよう。以下のプログラムでは、標準入力からの入力がある間(=EOFでない間)、入力された数を整数に変換し、2倍して表示する。
puts STDIN.gets.to_i * 2 while !STDIN.eof
|
while
修飾子を使った場合)STDIN.eof
は、標準入力からの入力が終了したことを表す。!
は否定の演算子なので、このwhile
修飾子の節は「標準入力からの入力が終了していない間」という意味になる。STDIN.gets
は標準入力から入力された一行の文字列を取得することを表す。to_i
は、文字列を整数に変換するためのメソッドである。
while !
の部分はuntil
に書き換えることができる。until
修飾子を使って同じ意味のプログラムを表現すると以下のようになる。
puts STDIN.gets.to_i * 2 until STDIN.eof
|
until
の場合は、式がfalseである間(trueになるまで)繰り返す。したがって、標準入力からの入力が終了するまで繰り返す。
上記2つのコードの実行例は以下の通り。標準入力(キーボード)からの入力がputs
メソッドによりそのまま出力される。標準入力からの入力を終了させるには、WindowsのコマンドプロンプトではCtrl+Zキーを押してからEnterキーを押す。MacやLinuxのターミナルではCtrl+Dキーを押せばよい。
$ ruby sample001.rb
10
20
15
30
← Windowsの場合は[Ctrl]+[Z]キーの後、[Enter]キー、Mac/Linuxの場合は[Ctrl]+[D]キーを押す
$
|
プログラムを実行し、10と入力してEnterキーを押すと20が表示される。続いて15と入力してEnterキーを押すと30が表示される。標準入力からの入力を終了させると、繰り返し処理が終了する。
while/until修飾子による「後判断型」の繰り返し
繰り返して実行したい式が複数ある場合は、それらの式
をbegin
とend
で囲めばよい(リスト1.3)。
【構文】while/until修飾子を使った「後判断型」の繰り返し処理
begin
式……
end while|until 条件式
この場合は、後判断型の繰り返しになる(※詳しくは後掲のコラムを参照)。以下の例では0以上10未満の偶数を表示する。
i = 0
begin
puts i
i += 2
end while i < 10
|
begin
とend
で囲まれた範囲の後にwhile
節が書ける。変数i
の値は0から2ずつ増えていく。変数i
の値が10未満である間、繰り返される。なお、後判断型の繰り返し処理になるので、begin
とend
の範囲は少なくとも1回は実行される。
実行例は以下の通り。
$ ruby sample003.rb
0
2
4
6
8
$
|
プログラムを実行すると、変数i
の値が表示される。動作を確認するためだけなので、何の変哲もない結果だが、変数i
の値が10未満である間は繰り返されていることがわかる。
while/until修飾子による「前判断型」/「後判断型」繰り返しの違い
前判断型と後判断型で違いが生じるのは、最初から繰り返し処理を終了させる条件が成立している場合である。先ほどの例で、i
の値が10から始まるものして、以下のプログラムで違いを確認しておこう。
puts "前判断型の場合"
i = 10
puts i += 2 while i < 10
puts "後判断型の場合"
i = 10
begin puts i += 2 end while i < 10
|
繰り返し処理を実行する前から、繰り返しを終了させる条件が成立していると、前判断型では繰り返しの中の式は全く実行されないが、後判断型では繰り返しの中の式が1回だけ実行され、その後で繰り返しを終了するかどうかが判定される。
実行例は以下の通り。
$ ruby sample004.rb
前判断型の場合
後判断型の場合
12
|
繰り返しを終了させる条件が最初から成立している場合、前判断型では繰り返しの中の式が実行されないので、結果は何も表示されない。後判断型では繰り返しの中の式が1回だけ実行されるので、変数i
の値に2を加えた値(12)が表示される。
while
修飾子やuntil
修飾子は条件式を修飾子の後に書くにもかかわらず、常に「後判断型」というわけではないことに注意が必要だ。式が1つだけの場合は「前判断型」になり、複数の式をbegin
とend
で囲んだ場合は「後判断型」になる。
なお、ここではwhile
修飾子の例で見たが、until
修飾子の場合でも同様である。
【コラム】while文とuntil文の書き方
繰り返し処理はプログラミングの基本的な知識なので、初歩から解説することは避け、書き方を簡単にまとめておくにとどめる。なお、本稿ではwhile
文、until
文と表記しているが、正確にはそれらは式であり、通常はnilを返す。ただし、break
に引数を指定して途中で繰り返しを抜けると、break
の引数を式の値として返す。
書き方1: 前判断型のwhile/until
【構文】while/until式を使った「前判断型」の繰り返し処理
while|until 条件式 [do]
式……
end
while
の場合は、条件式がtrueである間、式を繰り返して実行する。つまり、条件式
がfalseになると繰り返しを終了する。
一方、until
の場合は、条件式がfalseである間、式を繰り返して実行する。つまり、条件式
がtrueになると繰り返しを終了する。
式
の部分には複数の式を書いてもよい。なお、while
からend
までを1行で書く場合にはdo
は省略できないが、条件式
の後で改行する場合はdo
を省略できる。
書き方2: 後判断型のwhile/until
これは厳密には、while
/until
文ではなくwhile
/until
修飾子であり、構文的には前述の「【構文】while/until修飾子を使った「後判断型」の繰り返し処理」と全く同じものになる(※つまり以下は再掲)。
【構文】while/until修飾子を使った「後判断型」の繰り返し処理
begin
式……
end while|until 条件式
繰り返しを行う(終了させる)条件は、書き方1と同じだが、条件式を評価するのが式を実行した後になる点が異なる。
繰り返しを途中で抜けるbreakと次の繰り返しを実行するnext
何らかの条件に当てはまった場合に、繰り返しを途中で抜けたり、その繰り返しをスキップして次の繰り返しに移ったりしたいことがある。繰り返しを途中で抜ける場合にはbreak
を使い、次の繰り返しに移るにはnext
を使う。
break
以下の例は、リスト1.1のプログラムとほぼ同じ処理内容だが、数値データを入力せずにEnterキーだけを押すと繰り返し処理を抜け、プログラムを終了するようにしたものだ。
while !STDIN.eof
x = STDIN.gets
if x == "\n" then
break
end
puts x.to_i * 2
end
|
gets
メソッドで標準入力からデータを入力すると、末尾の改行文字も入力される。入力された文字が改行文字だけの場合、break
によって繰り返しを抜ける。
プログラムを実行すると、次のようになる。標準入力からの入力を終了させる方法だけでなく、Enterキーを押すだけでもプログラムが終了する。
$ ruby sample006.rb
10
20
15
30
← [Enter]キーを押すとプログラム終了
|
標準入力からの入力を終了させる方法以外にも、Enterキーを押すだけでもプログラムが終了するようになった。
next
繰り返しをスキップして次の繰り返し処理に移るには、基本的にはリスト1.5のbreak
をnext
に書き換えるだけでよい。リスト1.1のプログラムでは、データを入力せずにEnterキーだけを押すと、to_i
メソッドの働きにより数字以外の文字(厳密には改行文字)が0に変換され、0という値が表示されてしまう。そういった場合には何も表示されないようにしたものが以下のプログラムだ。ただし、改行文字の場合に処理をスキップするだけだと、"a"や"b"といった数字以外の文字を入力した場合に0が表示される。そこで、整数と見なせない文字を入力した場合にも、何も表示しないようにコードを追加しておいた。
def checkInt?(x)
Integer(x)
return true
rescue
return false
end
while !STDIN.eof
x = STDIN.gets
if x == "\n" || ! checkInt?(x) then
next
end
puts x.to_i * 2
end
|
checkInt?
メソッドは、文字列が整数に変換できるかどうかをチェックするメソッドである。trueかfalseを返すメソッドの場合、Rubyプログラミングの習慣としてメソッド名に?
を付けるので、ここでもそれに倣った名前としてある。
リスト1.6の前半(=checkInt?
メソッドの定義内容)では、文字列が整数に変換できなかったときに例外処理(rescue
節)を使ってfalseを返すようにしている。Integer
メソッドで整数に変換できなかった場合は、rescue
節に書かれたコードが実行されるので、falseが返されるというわけだ。実行例は以下の通り。
$ ruby sample007.rb
10
20
← [Enter]キーを押す
15
30
a ←数字以外の文字を入力する
35
70
← [Enter]キーを押すとプログラム終了
|
Enterキーを押すと、それ以降の処理がスキップされる。puts
による表示が実行されず、次の繰り返しに移り、入力ができるようになる。また、数字以外を入力しても同様に処理がスキップされ、次の入力ができるようになる。
まとめ
Rubyでは、while
文やuntil
文で前判断型または後判断型の繰り返し処理ができるほか、while
修飾子やuntil
修飾子を使った簡潔な記述も可能だ。while
修飾子やuntil
修飾子を使った場合の書き方で、1つの式では「前判断型」になるが、複数の式をbegin
とend
で囲むと「後判断型」に変わることに注意が必要だ。
※以下では、本稿の前後を合わせて5回分(第7回~第11回)のみ表示しています。
連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。
8. if修飾子/unless文/case文 ― ちょっと便利な条件分岐の構文とは?
Rubyには、if文のような一般的なもの以外にも、if修飾子/unless文/unless修飾子/case文といった便利な条件分岐の構文が用意されている。その基本的な使い方を解説。
9. 【現在、表示中】≫ while修飾子/until修飾子/while文/until文 ― ちょっと便利な繰り返し処理の構文とは?(1)
Rubyに用意されている繰り返し処理構文のうち、while文/until文の基本的な使い方と落とし穴を解説。また、while/until「修飾子」を使った簡潔な記述方法にも言及する。
10. for文 ― ちょっと便利な繰り返し処理の構文とは?(2)
Rubyに用意されている繰り返し処理の構文のうち、for文の基本的な使い方と配列と組み合わせた利用例を解説。範囲や配列を利用して一定の回数だけ繰り返して文を実行する方法や、配列全体を処理する方法を紹介する。
11. ブロック ― ちょっと便利な繰り返し処理の構文とは?(3)
Rubyに用意されている繰り返し処理の構文のうち「ブロック」を使えば、繰り返し処理をより簡潔に書ける。その基本的な使い方と、自作メソッドでの利用例を解説する。