Ruby Programming/Syntax/Literals
數值(Numeric)
編輯123 # 整數 -123 # 有號整號 1_123 # 整數 (忽略底線) -543 # 負整數 123_456_789_123_456_789 # 長整數 123.45 # 浮點數 1.2e-3 # 浮點數 (科學記號式) 0xaabb # 十六進位整數 0377 # 八進位整數 -0b1010 # 二進位補數 0b001_001 # 二進位整數 ?a # ASCII 字元 'a' (97) ?\C-a # Control-a (1) ?\M-a # Meta-a (225);這是 Macintosh 鍵盤按鍵。 ?\M-\C-a # Meta-Control-a (129);這是 Macintosh 鍵盤按鍵。
字串(String)
編輯Ruby 可以像數值資料般妥善處理字串。字串是一個被雙引號 ("..."
) 或單引號 ('...'
) 括起的內容。除此之外, Ruby 也可以 %q
或 %Q
自定括號符號。
雙引號和單引號在某些案例上具有不同的效果。由雙引號括起的字串允許以反斜線記號 (添加一個引導的反斜線 (\) 在字元前) 轉換該字元之意義 - 通稱轉義(escaping),也可以竄寫內容 (以 #{}
嵌入一段可估算的式子)。由單引號括起的字串不做這些解釋工作,除了 \' 和 \\;你將得到你所看到的。例如:
irb> puts "a\nb\nc" a b c => nil irb> puts 'a\nb\n' a\nb\nc => nil irb> "\n" => "\n" irb> '\n' => "\\n" irb> "\001" => "\001" irb> '\001' => "\\001" irb> "abcd #{5*3} efg" => "abcd 15 efg" irb> var = " abc " => " abc " irb> "1234#{var}5678" => "1234 abc 5678"
單引號括號
編輯單引號只允許兩個轉義字元
- \' – 單引號
- \\ – 單斜線
雙引號括號
編輯雙引號括起的字串允許以反斜線記號 (添加一個引導的反斜線 (\) 在字元前) 轉換該字元之意義,也可以竄寫內容 (以 #{} 嵌入一段可估算的式子)。
反斜線記號(Backslash Notation)
編輯範例:
"this is a\ntwo line string" "this is string with \"quotes\" word"
\n | 換行 (0x0a) | \s | 空格 (0x20) |
\r | 歸位(carriage return) (0x0d) | \nnn | 以八進位碼 nnn 表示一個字元 |
\t | 定位調整(tab) (0x09) | \xnn | 以十六進位碼 nn 表示一個字元 |
\v | 垂直定位(vertical tab) (0x0b) | \cx | control-x |
\f | 換頁 (0x0c) | \C-x | control-x |
\b | 退格(backspace) (0x08) | \M-x | meta-x |
\a | 嚮音/警示音 (0x07) | \M-\C-x | meta-control-x |
\e | Escape字元 (0x1b) | \x | 表示字元x 本身,即不轉義,例如: \" |
竄寫(Interpolation)
編輯以 #{expression}
語法在字串中嵌入一段式子,並以式子之估算值竄寫式子內容。記得,單引號括起的字串不理會竄寫。範例:
"1 + 2 = #{1 + 2}" #=> "1 + 2 = 3" '1 + 2 = #{1 + 2}' #=> "1 + 2 = #{1 + 2}"
式子 1+2 之計算結果為 3 ,以此值竄寫字串中之 #{ 1 + 2}
,故得 "1 + 2 = 3"。
幾乎所有 Ruby 式子都可以被嵌入。若被嵌入的式子中使用了不存在的變數 (尚未指派內容) ,則會引發 NameError 異常:
"trying to print #{undefined} variable"
NameError: undefined local variable or method `undefined' for main:Object
指令竄寫(Command Interpolation)
編輯指令竄寫是另一種竄寫作業,它使用反引號(`) - PC鍵盤上方數字鍵 1 左邊的按鍵符號 - 括住一段命令列指令,令系統執行指令後再擷取指令之輸出結果,最後以輸出結果竄寫指令內容並回傳為一字串,完成指令竄寫作業。由於指令內容必須為系統中存在之可執行程式,而可用之指令隨系統有所差異,故此方式未必可得到結果。
指令竄寫可以 %x 指定反引號(`)之替用符號。
範例 (Unix類系統):
d = `date` d_parts = d.split(' ') puts "Today is #{d_parts[0]}" %x(uname -a)
範例 (Windows系統):
exec_path = `echo %PATH%` paths = exec_path.split(';') %x[echo %OS%]
Alternate Notation
編輯'%'記號
Ruby 正式語法使用單引號與雙引號作為字串的括號。但 Ruby 從 Perl 語言中得到一個關於字串括號的古怪靈感:用 % (百分比字元) 指定字串的括號符號。例如: %[], %(), %{} 。除成對括弧符號外也可用單獨字元,如 %!!, %@@ 。在一個 % 字元後得指定一個修飾字元,諸如: %q[], %Q[], %x ,它們決定是否套用反斜線記號與竄寫規則。詳見單引號的替用者與雙引號的替用者。
範例:
'不套用竄寫與反斜線記號規則' "套用竄寫 #{interpolation}, 與反斜線記號 - \n" %q(不套用竄寫) %Q(套用竄寫 #{interpolation} 與反斜線記號 - \n) %(竄寫與反斜線) `echo "指令竄寫與反斜線"` %x(echo "指令竄寫與反斜線")
上述所有例子都有建置一個字串變數之效果。
當我們需要建置一個含有括號字元的字串卻又不想使用反斜線記號為括號字元轉義時,便經常運用'%'記號自行指定字串括號之符號。以自行指定的符號作為括號的替用者。
"string \"with\" quotes" #字串中含有雙引號("),必須以反斜線記號轉義 %{string "with" quotes} #以'%'記號指定大括弧{}為替用括號,便不需為雙引號轉義。 %!another string example! => "another string example" %@another "obnoxious" example@ => "another \"obnoxious\" example"
%r
可指定字樣規則式之邊界符號(/ 字元)的替用者。例如下列二式同義:
response.gsub! /<.*?>/, "" # 移除所有標籤 response.gsub! %r{<.*?>}, "" # 以 %r 指定大括弧為 / 符號的替用者。
%w
與%W
可指定陣列之邊界符號([ ])的替用者。還有一個附帶效果:將其中所有字面值都視為字串;單、雙引號將被視為字串的一部份而非字串的括號。
範例:
ar = ['123', 'abc', 'xyz'] => ["123", "abc", "xyz"] ar = %w< 123, abc, xyz > => ["123", "abc", "xyz"] ar = %w! 123, abc, xyz ! => ["123", "abc", "xyz"] ar = ['I\'s'] => ["I's"] ar = %w[ I's ] => ["I's"]
%記號修飾字元與效果表
編輯% | 指定字串括號的替用符號,並套用雙引號括號規則。詳見[[#雙引號的替用者|雙引號的替用 |
%Q | 指定字串括號的替用符號,並套用雙引號括號規則。詳見雙引號的替用者 |
%q | 指定字串括號的替用符號,並套用單引號括號規則。詳見單引號的替用者。 |
%r | 指定字樣規則式之邊界符號(/ 字元)的替用符號。 |
%s | 指定符號之邊界符號(:)的替用符號。 |
%w | 指定陣列之邊界符號([ ])的替用符號。 |
%W | 指定陣列之邊界符號([ ])的替用符號,並套用雙引號括號規則。 |
%x | 指定指令竄寫之邊界符號(`)的替用符號。 |
單引號的替用者
編輯舉例而言,我們想用字串表達檔案路徑名稱時,通常用單引號括起字串內容,如下所示:
puts 'c:\bus schedules\napolean\the portland bus schedule.txt'
用單引號括起字串內容時,不會轉義其中的 \b
, \n
, 和 \t
字元,故得以直率地表達檔案路徑。但如果檔案路徑名稱之中含有 '
時,我們就要寫成 \'
,如下所示:
puts 'c:\napolean\'s bus schedules\tomorrow\'s bus schedule.txt'
當字串中含有許多轉義字元時,將會降低程式的可讀性。所幸在 Ruby 中有更好的方式可用。你可以用 %q
自定括號,以 %q
自定之括號將套用單引號括號規則。你可以指定任何字元為括號。下列示範自定括號的用法,每一行都會印出同樣的文字 - "c:\napolean's documents\tomorrow's bus schedule.txt
" 。
puts %q!c:\napolean's documents\tomorrow's bus schedule.txt! puts %q/c:\napolean's documents\tomorrow's bus schedule.txt/ puts %q^c:\napolean's documents\tomorrow's bus schedule.txt^ puts %q(c:\napolean's documents\tomorrow's bus schedule.txt) puts %q{c:\napolean's documents\tomorrow's bus schedule.txt} puts %q<c:\napolean's documents\tomorrow's bus schedule.txt>
若你選擇的自定括號也同樣被用於字串文字,你仍然需要轉義。如下例以 #
為自定括號,但字串文字中也有一個 # 字元,此時就要寫成 \#
。
puts %q#c:\napolean's documents\tomorrow's \#9 bus schedule.txt#
當然我們用自定括號的意義在於避免這種情形,所以應儘量選用不會出現在字串文字中的字元做為自定括號。若你使用可成對的括弧字元為自定括號,你可用巢狀括弧而不需轉義。
puts %q(c:\napolean's documents\the (bus) schedule.txt) puts %q{c:\napolean's documents\the {bus} schedule.txt} puts %q<c:\napolean's documents\the <bus> schedule.txt>
雙引號的替用者
編輯%Q
允許你自定套用雙引號括號規則的括號符號,其用法如同 %q
。
print %Q^Say:\tHello world\n\tHello world\n^ print %Q(Say:\tHello world\n\tHello world\n)
你同樣可以在其中嵌入 Ruby 的式子竄寫字串內容。
name = 'Charlie Brown' puts %Q!Say "Hello," #{name}.! puts %Q/What is "4 plus 5"? Answer: #{4+5}/
字樣規則式(Regular Expression)
編輯在 Unix 的傳統中,我們用一種被稱為字樣規則式(regular expressions)的樣式文法,表達字樣在字串中出現的規則。附帶一提,Regular expression 時常被譯為常規表示法,詞不達意。字樣規則式以下列字元和字元組合的奇妙字彙撰寫一個簡明扼要的樣式(pattern) ,用於測試一個字串是否與此字樣相符。
[] | 指定範圍 (例如: [a-z] 表示一個在 a 到 z 範圍內的字母) |
\w | 字母或十進位數之字元;與 [0-9A-Za-z] 相同 |
\W | 非字母與十進位數之字元 |
\s | 空白字元;與 [ \t\n\r\f] 相同 |
\S | 非空白字元 |
\d | 十進位數之字元;與 [0-9] 相同 |
\D | 非十進位數之字元 |
\b | 退格 (0x08) (若用於指定範圍時) |
\B | 單字邊界 (若不用於指定範圍時) |
* | 零到數個其前一符號的內容 |
+ | 一到數個其前一符號的內容 |
{m,n} | 最少 m 個且最多 n 個其前一符號的內容 |
? | 零到一個其前一符號的內容;與 {0,1} 相同 |
| | 符合 '|' 之前一符號或後一符號的內容 |
() | 分組。分組可以標示子樣式(subpattern),並依出現順序賦予可參照之變數名稱,如 $1, $2 。若不要賦予分組可參照之變數名稱,則應於開頭加上?: 指示不予編號,例如 /(?:\w+)/ 。
|
Ruby 和 Perl 一樣用斜線 (/) 包圍樣式內容而不是用引號。若你以前從未用過字樣規則式,它們或許看來散漫無章,但其中實有規律性存在。你應明智地花一些時間熟悉它們。它們具有強大及有效率的表達能力。當你需要進行樣式比對、搜尋、或其他文字之操縱時,它們將省去許多令人頭痛的事 (和許多行程式碼)。
舉個例子,假設我們想要測試一個字串是否符合此一描述:「以小寫 f 開始,緊跟着一個大寫字母;之後可能有一些廢話,只要其中沒有任何小寫字母。」 若你是個老練的 C 程序員,你腦海中或許已經寫下幾十行程式碼了。在 Ruby 中,你只需要用字樣規則 /^f[A-Z][^a-z]*$/
就可以測試你的字串了。
那麼「包含以角括號圈住的十六進位數字?」又如何?
irb> def chab(s) # "contains hex in angle brackets" irb> (s =~ /<0(x|x)(\d|[a-f]|[a-f])+>/) != nil irb> end => nil irb> chab "Not this one." => false irb> chab "Maybe this? {0x35}" # wrong kind of brackets => false irb> chab "Or this? <0x38z7e>" # bogus hex digit => false irb> chab "Okay, this: <0xfc0004>." => true
=~
是關於樣式規則比對的運算符號;它回傳符合樣式之字串內容的位置,若無符合者則回傳 nil
。
下列示範分組與分組變數:
'abc123xyz' =~ /([a-z]+)(\d+)([a-z]+)/ puts $1, $2 abc 123 'abc123xyz' =~ /([a-z]+)(?:\d+)([a-z]+)/ puts $1, $2 abc xyz
第二次比對時,指示第二個分組不賦予編號,故 $2 之值成為第三個分組結果。
儘管字樣規則式一眼看來像個謎語,你仍將很快地為它所能節省的許多表達功夫而感到滿意。
陣列(Array)
編輯陣列是由多個個體所組成的聚合體。你可以用方括弧 ([ ]) 建立一個陣列 ,並在其中以逗號分隔列出各個細項。也可用 Array.new
建立一個空白陣列,或是使用 %w 的替用語法。Ruby 的陣列可以容納各式各樣的個體。
我們可以數字作為索引,提取陣列的任何一部份。負號指示自陣列尾端取偏移量而非從陣列開頭。
array_one = Array.new array_two = [] # shorthand for Array.new array_three = ["a", "b", "c"] # array_three contains "a", "b" and "c" array_four = %w'a b c' # array_four also contains "a", "b" and "c" array_three[0] # => "a" array_three[2] # => "c" array_three[-2] # => "b" array_four[0] # => "a" array_four[1,2] # => ["b", "c"]
有二種快速建立陣列的方式。一種使用 %w 的替用語法;另一種是字串與陣列互轉:字串可用split
方法轉成陣列,陣列可用join
方法轉成字串。
array_one = %w'apple orange pear' # => ["apple", "orange", "pear"] array_two = 'apple orange pear'.split # => ["apple", "orange", "pear"] array_one == array_two # => true array_three = %w'dog:cat:bird' # => ["dog:cat:bird"] array_four = 'dog:cat:bird'.split(':') # => ["dog", "cat", "bird"] array_three == array_four # => false string_one = array_one.join(',') # => "apple,orange,pear" array_five = string_one.split(',') # => ["apple", "orange", "pear"] array_five == array_one # => true
雜湊表(Hash)
編輯有種稱為「關聯索引陣列(associative array)」的特殊陣列,它不是以有序的數字索引提取內容,而是以無序的鍵值(keys) - 或稱關鍵字。這種陣列有時又稱之為雜湊表(hash)或字典(dictionary);在 Ruby 的世界中,我們慣用雜湊表一詞。我們可以用一對大括號 ({ }) 括起各對細項 (鍵值 => 內容
) 以建立雜湊表;也可用 Hash.new
建立一個空白雜湊表。在編程時,用雜湊表的時機將比用陣列的時機要多。
hash_one = Hash.new hash_two = {} # shorthand for Hash.new hash_three = {"a" => 1, "b" => 2, "c" => 3} #=> {"a"=>1, "b"=>2, "c"=>3}
符號常被當成是雜湊表的鍵值(可以更快存取),所以您可能看到下列定義方式:
hash_sym = { :a => 1, :b => 2, :c => 3} #=> {:b=>2, :c=>3, :a=>1}
範圍(Range)
編輯範圍是一種表示所有預期值子集的型態。確切而言,所有預期值為處於起始值至終止值之間的任意值。範圍有兩種表達型式:
起始值..終止值
: 意義為'起始值 <= 預期值 <= 終止值'起始值...終止值
: 意義為'起始值 <= 預期值 < 終止值' (不含終止值)
例如下列範圍:
- 所有介於 0 到 5 之間的整數。
- 所有介於 0 到 1 之間的數 (含非整數) ,但不含 1 。
- 所有介於 't' 到 'y' 之間的英文字母。
以 Ruby 表達如:
0..5 0.0...1.0 't'..'y'
範圍的表達方式為遞增,不是遞減。所以下列寫法錯誤,將得到一個空集合:
5..0
範圍之集合僅可為相同類或有共同父祖類之實例,且必須可比較(Comparable),即實作了 <=>
方法。範圍實際上為 Range 類之實例,故具有該類之行為。下列以===
方法判斷右值是否在範圍之中:
r = 0..5 puts r === 4 # => true puts r === 7 # => false
關於 Range 類所有方法之詳細資訊,請參考Range class reference。
符號(Symbol)
編輯將冒號(:)加在識別字前,即為符號。符號是一種識別用的記號,經常於雜湊表中作為鍵值。可用%s指定冒號之替用符號。
範例:
:abc # just mark here as 'abc' t1 = {:name => 'john', :age => 20} puts t1[:name] t2 = {%s'name' => 'smith', %s[age] => 16} puts t2[:name]
一般而言,以符號作為雜湊表之鍵值時效能較佳。因為以字串為鍵值時,Ruby 必須計算字串的雜湊值;以符號為鍵值時則不需計算。熟悉 C/C++ 語言的程序員可以 enum 與 map 之差異比對:以符號為鍵值類似以 enum 建立表;以字串為鍵值類似以 map class 建立表。兩者效能差異顯著。