Ruby TIPS

Ruby TIPS

while修飾子/until修飾子/while文/until文 ― ちょっと便利な繰り返し処理の構文とは?(1)

2016年7月11日

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倍して表示する。

sample001.rb
puts STDIN.gets.to_i * 2 while !STDIN.eof
リスト1.1 入力された整数の値を2倍して表示する(while修飾子を使った場合)

STDIN.eofは、標準入力からの入力が終了したことを表す。!は否定の演算子なので、このwhile修飾子の節は「標準入力からの入力が終了していない間」という意味になる。STDIN.getsは標準入力から入力された一行の文字列を取得することを表す。to_iは、文字列を整数に変換するためのメソッドである。

 while !の部分はuntilに書き換えることができる。until修飾子を使って同じ意味のプログラムを表現すると以下のようになる。

sample002.rb
puts STDIN.gets.to_i * 2 until STDIN.eof
リスト1.2 入力された整数の値を2倍して出力する(until修飾子を使った場合)

untilの場合は、式がfalseである間(trueになるまで)繰り返す。したがって、標準入力からの入力が終了するまで繰り返す。

 上記2つのコードの実行例は以下の通り。標準入力(キーボード)からの入力がputsメソッドによりそのまま出力される。標準入力からの入力を終了させるには、WindowsのコマンドプロンプトではCtrlZキーを押してからEnterキーを押す。MacやLinuxのターミナルではCtrlDキーを押せばよい。

コンソール
$ ruby sample001.rb 
10
20
15
30
  ← Windowsの場合は[Ctrl]+[Z]キーの後、[Enter]キー、Mac/Linuxの場合は[Ctrl]+[D]キーを押す
$ 
実行例1.1 繰り返し処理のプログラムを実行する

プログラムを実行し、10と入力してEnterキーを押すと20が表示される。続いて15と入力してEnterキーを押すと30が表示される。標準入力からの入力を終了させると、繰り返し処理が終了する。

while/until修飾子による「後判断型」の繰り返し

 繰り返して実行したい式が複数ある場合は、それらのbeginendで囲めばよい(リスト1.3)。

【構文】while/until修飾子を使った「後判断型」の繰り返し処理

begin
  式……
end while|until 条件式

 この場合は、後判断型の繰り返しになる(詳しくは後掲のコラムを参照)。以下の例では0以上10未満の偶数を表示する。

sample003.rb
i = 0
begin
  puts i
  i += 2
end while i < 10
リスト1.3 beginとendで複数の式を囲む

beginendで囲まれた範囲の後にwhile節が書ける。変数iの値は0から2ずつ増えていく。変数iの値が10未満である間、繰り返される。なお、後判断型の繰り返し処理になるので、beginendの範囲は少なくとも1回は実行される。

 実行例は以下の通り。

コンソール
$ ruby sample003.rb 
0
2
4
6
8
$ 
実行例1.2 10未満の偶数を表示するプログラムの実行例

プログラムを実行すると、変数iの値が表示される。動作を確認するためだけなので、何の変哲もない結果だが、変数iの値が10未満である間は繰り返されていることがわかる。

while/until修飾子による「前判断型」/「後判断型」繰り返しの違い

 前判断型後判断型で違いが生じるのは、最初から繰り返し処理を終了させる条件が成立している場合である。先ほどの例で、iの値が10から始まるものして、以下のプログラムで違いを確認しておこう。

sample004.rb
puts "前判断型の場合"
i = 10
puts i += 2 while i < 10

puts "後判断型の場合"
i = 10
begin puts i += 2 end while i < 10
リスト1.4 前判断型と後判断型の違いを確認するためのプログラム

繰り返し処理を実行する前から、繰り返しを終了させる条件が成立していると、前判断型では繰り返しの中の式は全く実行されないが、後判断型では繰り返しの中の式が1回だけ実行され、その後で繰り返しを終了するかどうかが判定される。

 実行例は以下の通り。

コンソール
$ ruby sample004.rb
前判断型の場合
後判断型の場合
12
実行例1.3 プログラムを実行して前判断型と後判断型の繰り返し処理の違いを確認する

繰り返しを終了させる条件が最初から成立している場合、前判断型では繰り返しの中の式が実行されないので、結果は何も表示されない。後判断型では繰り返しの中の式が1回だけ実行されるので、変数iの値に2を加えた値(12)が表示される。

 while修飾子やuntil修飾子は条件式を修飾子の後に書くにもかかわらず、常に「後判断型」というわけではないことに注意が必要だ。式が1つだけの場合は「前判断型」になり、複数の式をbeginendで囲んだ場合は「後判断型」になる。

 なお、ここではwhile修飾子の例で見たが、until修飾子の場合でも同様である。

【コラム】while文とuntil文の書き方

 繰り返し処理はプログラミングの基本的な知識なので、初歩から解説することは避け、書き方を簡単にまとめておくにとどめる。なお、本稿ではwhileuntilと表記しているが、正確にはそれらは式であり、通常はnilを返す。ただし、breakに引数を指定して途中で繰り返しを抜けると、breakの引数を式の値として返す。

書き方1: 前判断型のwhile/until

【構文】while/until式を使った「前判断型」の繰り返し処理

while|until 条件式 [do]
  式……
end

 whileの場合は、条件式がtrueである間、式を繰り返して実行する。つまり、条件式falseになると繰り返しを終了する。

 一方、untilの場合は、条件式がfalseである間、式を繰り返して実行する。つまり、条件式trueになると繰り返しを終了する。

 の部分には複数の式を書いてもよい。なお、whileからendまでを1行で書く場合にはdoは省略できないが、条件式の後で改行する場合はdoを省略できる。

図1.1 書き方1のフローチャート

while文とuntil文の違いは、truefalseが逆になるということだけ。

書き方2: 後判断型のwhile/until

 これは厳密には、whileuntilではなくwhileuntil修飾子であり、構文的には前述の「【構文】while/until修飾子を使った「後判断型」の繰り返し処理」と全く同じものになる(つまり以下は再掲)。

【構文】while/until修飾子を使った「後判断型」の繰り返し処理

begin
  式……
end while|until 条件式

 繰り返しを行う(終了させる)条件は、書き方1と同じだが、条件式を評価するのが式を実行した後になる点が異なる。

図1.2 書き方2のフローチャート

後判断型の場合、式は少なくとも1回は実行される。

繰り返しを途中で抜けるbreakと次の繰り返しを実行するnext

 何らかの条件に当てはまった場合に、繰り返しを途中で抜けたり、その繰り返しをスキップして次の繰り返しに移ったりしたいことがある。繰り返しを途中で抜ける場合にはbreakを使い、次の繰り返しに移るにはnextを使う。

break

 以下の例は、リスト1.1のプログラムとほぼ同じ処理内容だが、数値データを入力せずにEnterキーだけを押すと繰り返し処理を抜け、プログラムを終了するようにしたものだ。

sample006.rb
while !STDIN.eof
  x = STDIN.gets
  if x == "\n" then
    break
  end
  puts x.to_i * 2 
end
リスト1.5 breakで繰り返しを抜ける

getsメソッドで標準入力からデータを入力すると、末尾の改行文字も入力される。入力された文字が改行文字だけの場合、breakによって繰り返しを抜ける。

 プログラムを実行すると、次のようになる。標準入力からの入力を終了させる方法だけでなく、Enterキーを押すだけでもプログラムが終了する。

コンソール
$ ruby sample006.rb
10
20
15
30
  ← [Enter]キーを押すとプログラム終了
実行例1.4 breakの動作を確認する

標準入力からの入力を終了させる方法以外にも、Enterキーを押すだけでもプログラムが終了するようになった。

next

 繰り返しをスキップして次の繰り返し処理に移るには、基本的にはリスト1.5のbreaknextに書き換えるだけでよい。リスト1.1のプログラムでは、データを入力せずにEnterキーだけを押すと、to_iメソッドの働きにより数字以外の文字(厳密には改行文字)が0に変換され、0という値が表示されてしまう。そういった場合には何も表示されないようにしたものが以下のプログラムだ。ただし、改行文字の場合に処理をスキップするだけだと、"a""b"といった数字以外の文字を入力した場合に0が表示される。そこで、整数と見なせない文字を入力した場合にも、何も表示しないようにコードを追加しておいた。

sample007.rb
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
リスト1.6 nextで繰り返しをスキップする

checkInt?メソッドは、文字列が整数に変換できるかどうかをチェックするメソッドである。truefalseを返すメソッドの場合、Rubyプログラミングの習慣としてメソッド名に? を付けるので、ここでもそれに倣った名前としてある。

 リスト1.6の前半(=checkInt?メソッドの定義内容)では、文字列が整数に変換できなかったときに例外処理(rescue節)を使ってfalseを返すようにしている。Integerメソッドで整数に変換できなかった場合は、rescue節に書かれたコードが実行されるので、falseが返されるというわけだ。実行例は以下の通り。

コンソール
$ ruby sample007.rb
10
20
   ← [Enter]キーを押す
15
30
a   ←数字以外の文字を入力する
35
70
  ← [Enter]キーを押すとプログラム終了
実行例1.5 nextの動作を確認する

Enterキーを押すと、それ以降の処理がスキップされる。putsによる表示が実行されず、次の繰り返しに移り、入力ができるようになる。また、数字以外を入力しても同様に処理がスキップされ、次の入力ができるようになる。

まとめ

 Rubyでは、while文やuntil文で前判断型または後判断型の繰り返し処理ができるほか、while修飾子やuntil修飾子を使った簡潔な記述も可能だ。while修飾子やuntil修飾子を使った場合の書き方で、1つの式では「前判断型」になるが、複数の式をbeginendで囲むと「後判断型」に変わることに注意が必要だ。

処理対象:while修飾子|until修飾子|while文|until文|break|next カテゴリ:文法 > 制御構造 > 繰り返し

※以下では、本稿の前後を合わせて5回分(第7回~第11回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

7. 複素数(Complexクラス)を活用するには?

組み込みライブラリに含まれるComplexクラスによる基本的な複素数の取り扱い方、複素数の四則演算、平面上の点(ベクトル)の操作方法を説明する。

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に用意されている繰り返し処理の構文のうち「ブロック」を使えば、繰り返し処理をより簡潔に書ける。その基本的な使い方と、自作メソッドでの利用例を解説する。

GrapeCity Garage 記事内容の紹介

Azure Central の記事内容の紹介

Twitterでつぶやこう!


Build Insider賛同企業・団体

Build Insiderは、以下の企業・団体の支援を受けて活動しています(募集概要)。

ゴールドレベル

  • 日本マイクロソフト株式会社
  • グレープシティ株式会社