# **第 6 章 循環**
與條件判斷一樣,循環也遍布于程序的各個角落,是程序中不可缺少的重要組成部分。本章我們將會探討:
-
**程序中的循環是什么**
-
**寫循環時需要注意的事項**
-
**循環的種類及其寫法**
### **6.1 循環的基礎**
我們在編寫程序時,常常遇到“希望這個處理重復執行多次”的情況。例如:
- **希望同樣的處理執行 X 次**
更復雜點的例子有:
-
**用其他對象置換數組里的所有元素;**
-
**在達成某條件之前,一直重復執行處理。**
這時,我們都需要用到循環。
接下來,我們將會介紹 Ruby 中基本的循環結構。其中比較特別的是,除了用傳統的循環語句實現循環外,我們還能用方法來實現循環,也就是說我們可以根據自己的需要定制循環方法。關于如何定制循環 , 我們會在第 11 章再詳細說明,這里我們先介紹一些預定義的循環語法結構。
### **6.2 循環時的注意事項**
下面兩點是循環時必須注意的。
-
**循環的主體是什么**
-
**停止循環的條件是什么**
大家也許會認為,我們自己寫的循環處理,“循環的主體是什么”我們自己總會知道吧。但是,實際編寫程序時,稍不注意就會發生把不應該循環的處理加入到循環中這樣的錯誤。而且,如果是循環里再嵌套循環的結構,在哪里做怎么樣的循環、循環的結果怎么處理等都可能會使程序變得難以讀懂。
另外,如果把“停止循環的條件”弄錯了,有可能會發生處理無法終止,或者處理還沒完成但已經跳出循環等這樣的情況。大家寫循環結構時務必注意上述兩點,避免發生錯誤。
### **6.3 實現循環的方法**
Ruby 中有兩種實現循環的方法。
-
**使用循環語句**
利用 Ruby 提供現有的循環語句,可以滿足大部分循環處理的需求。
-
**使用方法實現循環**
將塊傳給方法,然后在塊里面寫上需要循環的處理。一般我們在為了某種特定目的而需要定制循環結構時,才使用方法來實現循環。
下面是我們接下來要介紹的六種循環語句或方法。
-
**`times` 方法**
-
**`while` 語句**
-
**`each` 方法**
-
**`for` 語句**
-
**`until` 語句**
-
**`loop` 方法**
Ruby 的常用循環結構就介紹到這里,接下來就讓我們來具體看看如何使用這些語句或方法實現循環。
### **6.4 times 方法**
如果只是單純執行一定次數的處理,用 `times` 方法可以很輕松實現。
假設我們希望把“滿地油菜花”這個字符串連續輸出 7 次。
**代碼清單 6.1 times.rb**
~~~
7.times do
puts "滿地油菜花"
end
~~~
> **執行示例**
~~~
> ruby times.rb
滿地油菜花
滿地油菜花
滿地油菜花
滿地油菜花
滿地油菜花
滿地油菜花
滿地油菜花
~~~
使用 times 方法實現循環時,需要用到塊 `do ~ end`。
**循環次數`.times do`
希望循環的處理
`end`**
塊的 `do ~ end` 部分可以用`{~}`代替,像下面這樣:
**循環次數`.times {`
希望循環的處理
`}`**
在 `times` 方法的塊里,也是可以獲知當前的循環次數的。
~~~
10.times do |i|
┊
end
~~~
這樣,就可以把當前的循環次數賦值給變量 `i`。我們來看看實際的例子(代碼清單 6.2)。
**代碼清單 6.2 times2.rb**
~~~
5.times do |i|
puts "第#{i} 次的循環。"
end
~~~
> **執行示例**
~~~
> ruby times2.rb
第 0 次的循環。
第 1 次的循環。
第 2 次的循環。
第 3 次的循環。
第 4 次的循環。
~~~
請注意循環的次數是從 0 開始計算的。把循環次數的初始值設為 `1` 不失為一個好方法,但可惜我們不能這么做,因此我們只能在塊里面對循環次數做調整(代碼清單 6.3)。
**代碼清單 6.3 times3.rb**
~~~
5.times do |i|
puts "第#{i+1} 次的循環。"
end
~~~
> **執行示例**
~~~
> ruby times3.rb
第 0 次的循環。
第 1 次的循環。
第 2 次的循環。
第 3 次的循環。
第 4 次的循環。
~~~
但是,這樣的寫法會使變量 `i` 的值與實際輸出的值產生差異。從降低程序復雜度來看,這并不是一個好的的編程習慣。若是對循環次數比較在意時,我們不必勉強使用 `times` 方法,可使用下面即將介紹的 `for` 語句和 `while` 語句。
### **6.5 for 語句**
`for` 語句同樣是用于實現循環的。需要注意的是,與剛才介紹的 `times` 方法不同,`for` 并不是方法,而是 Ruby 提供的循環控制語句。
以下是使用 `for` 語句的典型示例(代碼清單 6.4)。
**代碼清單 6.4 for.rb**
~~~
1: sum = 0
2: for i in 1..5
3: sum = sum + i
4: end
5: puts sum
~~~
> **執行示例**
~~~
> ruby for.rb
15
~~~
這是一個求從 1 到 5 累加的程序。`for` 語句的結構如下所示:
**`for` 變量 `in` 開始時的數值`..`結束時的數值 `do`
希望循環的處理
`end`**
※ 可以省略 `do`
我們回顧一下程序代碼清單 6.4。程序第 1 行將 0 賦值給變量 `sum`,程序第 5 行輸出變量 `sum` 的值并換行。
第 2 行到第 4 行的 `for` 語句指定變量 `i` 的范圍是從 1 到 5。也就是說,程序一邊從 1 到 5 改變變量 `i` 的值,一邊執行 `sum = sum + i`。如果不使用循環語句,這個程序可以改寫為:
~~~
sum = 0
sum = sum + 1
sum = sum + 2
sum = sum + 3
sum = sum + 4
sum = sum + 5
puts sum
~~~
`for` 語句與 `times` 方法不一樣,循環的開始值和結束值可以任意指定。例如,我們想計算從變量 `from` 到變量 `to` 累加的總數,使用 `times` 方法的程序為:
~~~
from = 10
to = 20
sum = 0
(to - from + 1).times do |i|
sum = sum + (i + from)
end
puts sum
~~~
使用 for 語句的程序為:
~~~
from = 10
to = 20
sum = 0
for i in from..to
sum = sum + i
end
puts sum
~~~
使用 `for` 語句后的程序變得更加簡單了。
另外,`sum = sum + i` 這個式子也有更簡單的寫法:
~~~
sum += i
~~~
本例是加法的簡寫,做減法、乘法時也同樣可以做這樣的省略。
~~~
a -= b
a *= b
~~~
第 9 章我們會再詳細討論這方面的內容,現在暫時先記著有這么一個省略寫法就可以了。
### **6.6 普通的 for 語句**
其實上一節介紹的是 `for` 語句的特殊用法,普通的 `for` 語句如下所示:
**`for` 變量 `in` 對象 `do`
希望循環的處理
`end`**
※ 可以省略 `do`
可以看出,`in` 后面的部分和之前介紹的有點不同。
但和之前的 `for` 語句相比也并非完全不一樣。實際上,.. 或者 ... 都是創建范圍對象時所需的符號。
當然,并非任何對象都可以指定給 `for` 語句使用。下面是使用數組對象的例子。
**代碼清單 6.5 for_names.rb**
~~~
names = ["awk", "Perl", "Python", "Ruby"]
for name in names
puts name
end
~~~
> **執行示例**
~~~
> ruby for_names.rb
awk
Perl
Python
Ruby
~~~
本例中,循環遍歷各數組的元素,并各自將其輸出。
### **6.7 while 語句**
不管哪種類型的循環,`while` 語句都可以勝任,`while` 語句的結構如下:
**`while` 條件 `do`
希望循環的處理
`end`**
※ 可以省略 `do`

這幾行程序的意思就是,只要條件成立,就會不斷地重復循環處理。我們來看看下面的示例(代碼清單 6.6)。
**代碼清單 6.6 while.rb**
~~~
i = 1
while i < 3
puts i
i += 1
end
~~~
> **執行示例**
~~~
> ruby while.rb
1
2
~~~
本例為什么會得出這樣的結果呢。首先,程序將 1 賦值給變量 `i`,這時 `i` 的值為 1。接下來 `while` 語句循環處理以下內容:
1. **執行 `i < 3` 的比較。**
2. **比較結果為真(也就是 `i` 比 3 小)時,程序執行 `puts i` 和 `i += 1`。比較結果為假(也就是 `i` 大于等于 3)時,程序跳出 `while` 循環,不執行任何內容。**
3. **返回 1 處理。**
首次循環,由于 `i` 的初始值為 1,因此程序執行 `puts 1`。第 2 次循環,`i` 的值為 2,比 3 小,因此程序執行 `puts 2`。當程序執行到第 3 次循環,i 的值為 3,比 3 小的條件不成立,也就是說比較結果為假,因此,程序跳出 `while` 循環,并終止所有處理。
我們再來寫一個使用 `while` 語句的程序。
把之前使用 `for` 語句寫的程序(代碼清單 6.4),改寫為使用 `while` 語句程序(代碼清單 6.7)。
**代碼清單 6.7 while2.rb**
~~~
sum = 0
i = 1
while i <= 5
sum += i
i += 1
end
puts sum
~~~
這時與使用 `for` 語句的程序有細微的區別。首先,變量 `i` 的條件指定方式不一樣。`for` 語句的例子通過 `1..5` 指定條件的范圍。`while` 語句使用比較運算符 <=,指定“`i` 小于等于 5 時(循環)”的條件。
另外,`i` 的累加方式也不一樣。`while` 語句的例子在程序里直接寫出了 `i` 是如何進行加 1 處理的——`i += 1`。而 `for` 語句的例子并不需要在程序里直接寫如何對 `i` 進行操作,自動在每次循環后對 i 進行加 1 處理。
就像這個例子一樣,只要 `for` 語句能實現的循環,我們沒必要特意將它改寫為 `while` 語句。程序代碼清單 6.8 是使用 `while` 語句反而會更便于理解的一個例子。
**代碼清單 6.8 while3.rb**
~~~
sum = 0
i = 1
while sum < 50
sum += i
i += 1
end
puts sum
~~~
在這個例子里,作為循環條件的不是變量 `i`,而是變量 `sum`。循環條件現在變為“`sum` 小于 50 時執行循環處理”。一般來說,不通過計算,我們并不知道 `i` 的值為多少時 `sum` 的值才會超過 50,因此這種情況下使用 `for` 語句的循環反而會讓程序變得難懂。
有時 `for` 語句寫的程序易懂,有時候 `while` 語句寫的程序易懂。我們會在本章的最后說明,如何區別使用 `for` 語句和 `while` 語句。
### **6.8 until 語句**
與 `if` 語句相對的有 `unless` 語句,同樣地,與 `while` 語句相對的有 `until` 語句。`until` 語句的結構與 `while` 語句完全一樣,只是條件判斷剛好相反,不滿足條件時才執行循環處理。換句話說,`while` 語句是一直執行循環處理,直到條件不成立為止;`until` 語句是一直執行循環處理,直到條件成立為止。
**`until` 條件 `do`
希望循環的處理
`end`**
※ 可以省略 `do`

代碼清單 6.9 是使用了 `until` 語句的程序。
**代碼清單 6.9 until.rb**
~~~
sum = 0
i = 1
until sum >= 50
sum += i
i+= 1
end
puts sum
~~~
本例是將使用 `while` 語句的程序(代碼清單 6.8)用 `until` 語句改寫了,與 `while` 語句所使用的條件剛好相反。
其實,在 `while` 語句的條件上使用表示否定的運算符 !,也能達到和 `until` 語句相同的效果。
**代碼清單 6.10 while_not.rb**
~~~
sum = 0
i = 1
while !(sum >= 50)
sum += i
i += 1
end
puts sum
~~~
雖然可以使用 `while` 語句的否定形式代替 `until` 語句。但是,有時對一些比較復雜的條件表達式使用否定,反而會不直觀,影響程序理解,在這種情況下,我們應該考慮使用 `until` 語句。
### **6.9 each 方法**
`each` 方法將對象集合里的對象逐個取出,這與 `for` 語句循環取出數組元素非常相似。實際上,我們可以非常簡單地將使用 `for` 語句的程序(代碼清單 6.5)改寫為使用 `each` 方法的程序(代碼清單 6.11)。
**代碼清單 6.11 each_names.rb**
~~~
names = ["awk","Perl","Python","Ruby"]
names.each do |name|
puts name
end
~~~
`each` 方法的結構如下:
**對象`.each do` | 變量 |
希望循環的處理
`end`**
在說明 `times` 方法我們曾提到過,塊的 `do` ~ `end` 部分可換成 { ~ }。
**對象.`each {`| 變量 |
希望循環的處理
`}`**
這與下面的程序的效果是幾乎一樣。
**`for` 變量 `in` 對象
希望循環的處理
`end`**
在 Ruby 內部,`for` 語句是用 `each` 方法來實現的。因此,可以使用 `each` 方法的對象,同樣也可以指定為 `for` 語句的循環對象。
在介紹 `for` 語句時我們舉過使用范圍對象的例子(代碼清單 6.4),我們試著用 `each` 方法改寫一下。
**代碼清單 6.12 each.rb**
~~~
sum = 0
(1..5).each do |i|
sum= sum + i
end
puts sum
~~~
像本例這樣,我們可以輕松互相改寫兩種用法。那到底什么時候該用 `for` 語句,什么時候該用 `each` 方法呢,我們將在本章的最后討論這個問題。
### **6.10 loop 方法**
還有一種循環的方法,沒有終止循環條件,只是不斷執行循環處理。Ruby 中的 `loop` 就是這樣的循環方法。
~~~
loop do
print "Ruby"
end
~~~
執行上面的程序后,整個屏幕會不停的輸出文字 `Ruby`。為了避免這樣的情況發生,在實際使用 `loop` 方法時,我們需要用到接下來將要介紹的 `break`,使程序可以中途跳出循環。
> **備注** 程序不小心執行了死循環時,我們可以使用 CTRL + c 來強行終止程序。
### **6.11 循環控制**
在進行循環處理的途中,我們可以控制程序馬上終止循環,或者跳到下一個循環等。Ruby 提供了如下表(表 6.1)所示的三種控制循環的命令。
**表 6.1 循環控制命令**
<table border="1" data-line-num="407 408 409 410 411 412" width="90%"><thead><tr><th> <p class="表頭單元格">命令</p> </th> <th> <p class="表頭單元格">用途</p> </th> </tr></thead><tbody><tr><td> <p class="表格單元格">break</p> </td> <td> <p class="表格單元格">終止程序,跳出循環</p> </td> </tr><tr><td> <p class="表格單元格">next</p> </td> <td> <p class="表格單元格">跳到下一次循環</p> </td> </tr><tr><td> <p class="表格單元格">redo</p> </td> <td> <p class="表格單元格">在相同的條件下重復剛才的處理</p> </td> </tr></tbody></table>
在控制循環的命令中,可能不太容易區分使用 `next` 和 `redo`。借著下面的例子(代碼清單 6.13),我們來介紹一下如何區分這三種循環命令。
**代碼清單 6.13 break_next_redo.rb**
~~~
1: puts "break 的例子:"
2: i = 0
3: ["Perl", "Python", "Ruby", "Scheme"].each do |lang|
4: i += 1
5: if i == 3
6: break
7: end
8: p [i,lang]
9: end
10:
11: puts "next 的例子:"
12: i = 0
13: ["Perl", "Python", "Ruby", "Scheme"].each do |lang|
14: i += 1
15: if i == 3
16: next
17: end
18: p [i,lang]
19: end
20:
21: puts "redo 的例子:"
22: i = 0
23: ["Perl", "Python", "Ruby", "Scheme"].each do |lang|
24: i += 1
25: if i == 3
26: redo
27: end
28: p [i,lang]
29: end
~~~
我們來看看本例中的 `break`、`next`、`redo` 有什么不同。程序由三部分組成,除了 `break`、`next`、`redo` 這三部分的代碼外,其他地方都是相同的。下面是執行后的結果。
> **執行示例**
~~~
> ruby break_next_redo.rb
break 的例子:
[1, "Perl"]
[2, "Python"]
next 的例子:
[1, "Perl"]
[2, "Python"]
[4, "Scheme"]
redo 的例子:
[1, "Perl"]
[2, "Python"]
[4, "Ruby"]
[5, "Scheme"]
~~~
### **6.11.1 break**
`break` 會終止全體程序。在代碼清單 6.13 中,`i` 為 3 時,程序會執行第 6 行的 `break`(圖 6.1)。執行 `break` 后,程序跳出 `each` 方法循環,前進至程序的第 10 行。因此,程序沒有輸出 `Ruby` 和 `Scheme`。

**圖 6.1 break**
我們再來介紹一個關于 `break` 的例子。程序代碼清單 6.14 對第 3 章的 simple_grep.rb 做了點小修改,使程序最多只能輸出 10 行匹配到的內容。匹配的時候,累加變量 `matches`,當達到 `max_matches` 時,程序就會終止 `each_line` 方法的循環。
**代碼清單 6.14 ten_lines_grep.rb**
~~~
pattern = Regexp.new(ARGV[0])
filename = ARGV[1]
max_matches = 10 # 輸出的最大行數
matches = 0 # 已匹配的行數
file = File.open(filename)
file.each_line do |line|
if matches >= max_matches
break
end
if pattern =~ line
matches += 1
puts line
end
end
file.close
~~~
### **6.11.2 next**
使用 `next` 后,程序會忽略 `next` 后面的部分,跳到下一個循環開始的部分。在代碼清單 6.13 中,`i` 為 3 時在執行第 16 行的 `next` 后,程序前進到 `each` 方法的下個循環(圖 6.2)。也就是說,將 `Scheme` 賦值給 `lang`,并執行 `i += 1`。因此,程序并沒有輸出 `Ruby`,而是輸出了 `Scheme`。

**圖 6.2 next**
我們再來看看另外一個 `next` 的例子(代碼清單 6.15)。程序逐行讀取輸入的內容,忽略空行或者以 # 開頭的行,原封不動地輸出除此以外所有行的內容。
執行以下命令后,我們會得到去掉 fact.rb(代碼清單 6.16)的注釋和空行后的 stripped_fact.rb(代碼清單 6.17)。
~~~
> ruby strip.rb fact.rb > stripped_fact.rb
~~~
**代碼清單 6.15 strip.rb**
~~~
file = File.open(ARGV[0])
file.each_line do |line|
next if /^\s*$/ =~ line # 空行
next if /^#/ =~ line # 以“#”開頭的行
puts line
end
file.close
~~~
**代碼清單 6.16 fact.rb**
~~~
# 求10 的階乘
ans = 1
for i in 1..10
ans *= i
end
# 輸出
puts "10! = #{ans}"
~~~
**代碼清單 6.17 stripped_fact.rb**
~~~
ans = 1
for i in 1..10
ans *= i
end
puts "10! = #{ans}"
~~~
### **6.11.3 redo**
`redo` 與 `next` 非常像,與 `next` 的不同之處是,`redo` 會再執行一次相同的循環。
在代碼清單 6.13 中,與 `next` 時的情況不同,`redo` 會輸出 `Ruby`。這是由于,`i` 為 3 時就執行了第 26 行的 `redo`,程序只是返回循環的開頭,也就是從程序的第 24 行的 `i += 1` 部分開始重新再執行處理,所以 `lang` 的值并沒有從 `Ruby` 變為 `Scheme`。由于重復執行了 `i += 1`,`i` 的值變為 4,這樣 `if` 語句的條件 `i == 3` 就不成立了,`redo` 也不會再執行了,程序順理成章地輸出了 `[4, "Ruby"]` 以及 `[5, "Scheme"]`(圖 6.3)。

**圖 6.3 redo**
另外,大家要注意 `redo` 的使用方法,稍不留神就會在同樣的條件下,不斷地重復處理,陷入死循環中。
`break`、`next` 和 `redo` 中,一般比較常用是 `break` 和 `next`。大家應該熟練掌握這兩個命令的用法。即使是 Ruby 默認提供的庫里面,實際上也很難找到 `redo` 的蹤影,所以當我們在希望使用 `redo` 時,應該好好考慮是否真的有必要使用 `redo`。
### **6.12 總結**
本章我們主要介紹了循環時所用的語句以及方法。
如果純粹只考慮實現循環功能,任何種類的循環都可以用 `while` 語句實現。講得極端一點,其他循環語句和方法根本也沒存在的必要。即便如此,那為什么 Ruby 還提供了那么豐富的循環語句和方法呢。這是因為,程序并不只是單純為了實現功能,同時還應該使代碼更便于讀寫,使人更容易理解。
為了使大家更快地熟悉循環的用法,我們在最初介紹循環語句和方法的一覽表中加上“主要用途”一欄(表 6.2),以供大家參考。
**表 6.2 循環語句、方法及其主要用途**
<table border="1" data-line-num="566 567 568 569 570 571 572 573 574" width="90%"><thead><tr><th> <p class="表頭單元格">?</p> </th> <th> <p class="表頭單元格">主要用途</p> </th> </tr></thead><tbody><tr><td> <p class="表格單元格"><code>times</code>方法</p> </td> <td> <p class="表格單元格">確定循環次數時使用</p> </td> </tr><tr><td> <p class="表格單元格"><code>for</code>語句</p> </td> <td> <p class="表格單元格">從對象取出元素時使用(each 的語法糖)</p> </td> </tr><tr><td> <p class="表格單元格"><code>while</code>語句</p> </td> <td> <p class="表格單元格">希望自由指定循環條件時使用</p> </td> </tr><tr><td> <p class="表格單元格"><code>until</code>語句</p> </td> <td> <p class="表格單元格">使用 while 語句使循環條件變得難懂時使用</p> </td> </tr><tr><td> <p class="表格單元格"><code>each</code>方法</p> </td> <td> <p class="表格單元格">從對象取出元素時使用</p> </td> </tr><tr><td> <p class="表格單元格"><code>loop</code>方法</p> </td> <td> <p class="表格單元格">不限制循環次數時使用</p> </td> </tr></tbody></table>
> **備注**
> 語法糖(syntax sugar),是指一種為了照顧一般人習慣而產生的特殊語法 1。例如,使用常規的語法調 用方法,那么加法運算應該寫成 `3.add(2)`。但是對于一般人來說,寫成 `3 + 2` 會更直觀,更簡明易懂。
> 語法糖并不會加強編程語言的任何功能,但是對于提高程序的易讀性來講是不可或缺的。
1即一種符合人的思維模式、工作習慣等,便于理解的“甜蜜”的語法。——譯者注
以上都是筆者個人意見,僅供大家參考。
確定循環次數時循環處理使用 `times` 方法,除此以外的大部分循環處理,根據情況選擇 `while` 語句或者 `each` 方法,一般也能寫出直觀易懂的程序。請大家先熟練掌握這三種循環方法。
> **專欄**
> **do~end 與 {~}**
> 在 `times` 方法的示例中,我們介紹了塊的兩種寫法,`do ~ end` 與 `{ ~ }`。從執行效果來看,兩種方法雖然沒有太大區別,但一般我們會遵守以下這個約定俗成的編碼規則:
> - > 程序是跨行寫的時候使用 **`do ~ end`**
> - > 程序寫在 1 行的時候用 **`{ ~ }`**
> 以 `times` 方法來舉例,會有以下兩種寫法。
~~~
10.times do |i|
puts i
end
~~~
> 或者,
~~~
10.times{|i| puts i}
~~~
> 剛開始大家可能會有點不習慣。我們可以這樣理解,`do ~ end` 表示程序要執行內容是多個處理的集合,而 `{ ~ }` 則表示程序需要執行的處理只有一個,即把整個帶塊的方法看作一個值。
> 如果用把 `do ~ end` 代碼合并在一起,程序會變成下面這樣:
~~~
10.times do |i| puts i end
~~~
> 以上寫法,怎么看都給人一種很難斷句的感覺。雖然實際上使用哪種寫法都不會影響程序的運行,但在剛開始編寫程序時,還是建議大家先遵守這個編碼規則。
- 推薦序
- 譯者序
- 前言
- 本書的讀者對象
- 第 1 部分 Ruby 初體驗
- 第 1 章 Ruby 初探
- 第 2 章 便利的對象
- 第 3 章 創建命令
- 第 2 部分 Ruby 的基礎
- 第 4 章 對象、變量和常量
- 第 5 章 條件判斷
- 第 6 章 循環
- 第 7 章 方法
- 第 8 章 類和模塊
- 第 9 章 運算符
- 第 10 章 錯誤處理與異常
- 第 11 章 塊
- 第 3 部分 Ruby 的類
- 第 12 章 數值類
- 第 13 章 數組類
- 第 14 章 字符串類
- 第 15 章 散列類
- 第 16 章 正則表達式類
- 第 17 章 IO 類
- 第 18 章 File 類與 Dir 類
- 第 19 章 Encoding 類
- 第 20 章 Time 類與 Date 類
- 第 21 章 Proc 類
- 第 4 部分 動手制作工具
- 第 22 章 文本處理
- 第 23 章 檢索郵政編碼
- 附錄
- 附錄 A Ruby 運行環境的構建
- 附錄 B Ruby 參考集
- 后記
- 謝辭