Ruby 字符串對(duì)象
在 Ruby 中一切皆為對(duì)象,字符串當(dāng)然也不例外,本章中,您需要掌握字符串對(duì)象的創(chuàng)建方法,通過(guò)常見(jiàn)字符串實(shí)例方法的應(yīng)用來(lái)掌握字符串的實(shí)例方法。更重要的是,要理解字符串也是一個(gè)對(duì)象。
1. 什么是字符串對(duì)象
Ruby 中的 String 對(duì)象持有并操縱一個(gè)或多個(gè)字節(jié)的任意序列,通常表示代表人類語(yǔ)言的字符?!俜蕉x
一個(gè)或多個(gè)字節(jié)的任意序列可以理解為我們所熟悉的語(yǔ)言文字,例如:“小明“、“123“、“abc“、或者特殊符號(hào)等。字符串對(duì)象會(huì)顯示為我們?yōu)樗x予的文字。除此之外它可以對(duì)自身的文本內(nèi)容進(jìn)行截取、部分刪除、插入文字等操作,比如我想在 “abcd” 的末尾增加一個(gè) “e“,使這個(gè)字符串變成 “abcde”。
那么我們?nèi)绾蝿?chuàng)建一個(gè)字符串對(duì)象呢?
2. 字符串對(duì)象創(chuàng)建的方法
創(chuàng)建字符串對(duì)象的方法有很多種,最常用的創(chuàng)建方式是使用字符串文字:?jiǎn)我?hào)或雙引號(hào)之間的字符序列。兩種形式之間的區(qū)別是 Ruby 在構(gòu)造文字時(shí)對(duì)字符串進(jìn)行的處理量。
2.1 單引號(hào)
定義:?jiǎn)我?hào)內(nèi)存放文字的字符串對(duì)象。
除少數(shù)情況,單引號(hào)中的內(nèi)容將成為字符串的值。
使用場(chǎng)景:定義簡(jiǎn)單的字符串(不包含轉(zhuǎn)義符以及表達(dá)式插值操作)。
實(shí)例:
puts 'Hello Ruby!'
# ---- 輸出結(jié)果 ----
Hello Ruby!
當(dāng)您想要在單引號(hào)字符串中使用單引號(hào)'
時(shí),為了不要讓 Ruby 將輸入的單引號(hào)理解為終止符號(hào),您需要使用反斜杠\
。
實(shí)例:
# 輸出帶有'的單引號(hào)字符串
puts 'What\'s your name?'
# ---- 輸出結(jié)果 ----
What's your name?
兩個(gè)連續(xù)的反斜杠\\
被單個(gè)反斜杠替換。
實(shí)例:
# 在單引號(hào)字符串中輸入兩個(gè)反斜杠
puts 'escape using "\\"'
# ---- 輸出結(jié)果 ----
escape using "\"
2.2 雙引號(hào)
定義:雙引號(hào)內(nèi)存放文字的字符串對(duì)象。
使用場(chǎng)景:推薦用來(lái)定義復(fù)雜的字符串(包括轉(zhuǎn)義符或者表達(dá)式插值操作)。
實(shí)例:
# 輸出一段文字
puts "Hello Ruby!"
# ---- 輸出結(jié)果 ----
Hello Ruby!
當(dāng)使用雙引號(hào)創(chuàng)建字符串對(duì)象時(shí),首先他會(huì)查找以反斜杠\
開(kāi)頭的字符,進(jìn)行轉(zhuǎn)義操作,其中最常見(jiàn)轉(zhuǎn)義符為\n
,它叫做換行符,當(dāng)輸出包含換行符的字符串的時(shí)候,\n
會(huì)被強(qiáng)制轉(zhuǎn)換為換行。
實(shí)例:
# 輸出帶有換行符的字符串
puts "Goodnight,\nAlice"
# ---- 輸出結(jié)果 ----
Goodnight,
Alice
其次,雙引號(hào)字符串做的第二件事是表達(dá)式插值,在字符串中,#{表達(dá)式}
會(huì)被表達(dá)式的結(jié)果替換。
實(shí)例:
# 表達(dá)式插值
name = 'Alice' #定義一個(gè)局部變量name,這里的字符串單引號(hào)雙引號(hào)均可
puts "Goodnight, #{name}"
# ---- 輸出結(jié)果 ----
Goodnight, Alice
表達(dá)式也可以是數(shù)學(xué)運(yùn)算。
實(shí)例:
x, y, z = 12, 36, 72
puts "x 的值為 #{ x }"
puts "x + y 的值為 #{ x + y }"
puts "x + y + z 的平均值為 #{ (x + y + z)/3 }"
# ---- 輸出結(jié)果 ----
x 的值為 12
x + y 的值為 48
x + y + z 的平均值為 40
如果表達(dá)式只是全局變量$
,類變量@@
或實(shí)例變量@
,則可以省略花括號(hào)。變量類型將在之后章節(jié)給大家普及。
實(shí)例:
puts "This is line #$."
# ---- 輸出結(jié)果 ----
This is line 1
經(jīng)驗(yàn):除了#{}
這種表達(dá)式插值的形式,使用+
也可以進(jìn)行字符串拼接操作,但是要求進(jìn)行拼接的兩個(gè)變量的類型一定是字符串,否則會(huì)拋出異常,Ruby 會(huì)將#{}
表達(dá)式中的結(jié)果強(qiáng)制轉(zhuǎn)化為字符串,我們不需要關(guān)心變量的類型,只需要關(guān)心拼接的操作。所以,最好不使用+
來(lái)拼接字符串。
對(duì)比下面兩種情況:
x = 12
puts "x 的值為 #{x}"
# ---- 輸出結(jié)果 ----
x 的值為 12
x = 12
puts "x 的值為 " + x
# ---- 輸出結(jié)果 ----
Traceback (most recent call last):
1: from ruby.rb:2:in `<main>'
ruby.rb:2:in `+': no implicit conversion of Integer into String (TypeError)
而這樣就不會(huì)拋出異常:
x = 12
puts "x 的值為 " + x.to_s # 將12從數(shù)字轉(zhuǎn)化成字符串
# ---- 輸出結(jié)果 ----
x 的值為 12
2.3 %q和%Q
定義:%q
同單引號(hào)規(guī)則,%Q
同雙引號(hào)規(guī)則。
使用場(chǎng)景:定義多行字符串。
在q
和Q
之后的字符是分隔符,如果是[
、{
、(
、!
或<
則將讀取字符串,直到找到匹配的結(jié)束符號(hào),否則將一直讀取字符直到下一次出現(xiàn)相同的分隔符為止。
實(shí)例:
%q/生成單引號(hào)字符/ # 相當(dāng)于 '生成單引號(hào)字符'
%Q!生成雙引號(hào)字符! # 相當(dāng)于 "生成雙引號(hào)字符"
%Q{Seconds/day: #{24*60*60}} #相當(dāng)于 "Seconds/day: #{24*60*60}"
# ---- 輸出結(jié)果 ----
生成單引號(hào)字符
生成雙引號(hào)字符
Seconds/day: 86400
2.4 Heredoc
定義:Heredoc 是定義多行字符串,同時(shí)保持原始縮進(jìn)和格式的一種方法。
使用場(chǎng)景:這用于嵌入諸如 SQL 或 HTML 之類的代碼片段。
實(shí)例:
query = <<-SQL
SELECT * FROM food
WHERE healthy = true
SQL
# ---- 輸出結(jié)果 ----
"SELECT * FROM food\nWHERE healthy = true\n"
解釋:
您以符號(hào)<<-
開(kāi)頭,然后是代表此 Heredoc 名稱的單詞,然后是 Heredoc 內(nèi)容,然后在此文檔的最后用該單詞關(guān)閉 Heredoc。
3. 字符串實(shí)例方法應(yīng)用
String 可能是最大的內(nèi)置 Ruby 類,具有超過(guò) 75 種標(biāo)準(zhǔn)方法。我將在下面主要介紹最常用的實(shí)例方法。String類實(shí)例方法官方鏈接。
3.1 獲取字符串長(zhǎng)度
用來(lái)獲取字符串中字符的個(gè)數(shù)。
實(shí)例:
"ruby".length
# 或者
"ruby".size
# ---- 輸出結(jié)果 ----
4
3.2 檢查一個(gè)字符串是否為空
Tips:我們將空字符串定義為長(zhǎng)度為零的字符串。
實(shí)例:
"".empty?
# 相當(dāng)于
"".size == 0 # 但是empty?是更好的選擇
# ---- 輸出結(jié)果 ----
true
3.3 如何提取一個(gè)子字符串
子字符串(substring)是字符串的一小部分,如果您只想要該特定部分的字符串(例如開(kāi)頭,中間或結(jié)尾),則很有用。
一種方法是使用方括號(hào)內(nèi)的起始索引和多個(gè)字符,以逗號(hào)分隔:
實(shí)例:
string = "abc123" # 索引以0開(kāi)始,代表第一個(gè)字符
# 從索引0開(kāi)始截取3個(gè)字符
string[0,3]
# 從索引3開(kāi)始截取3個(gè)字符
string[3,3]
# ---- 輸出結(jié)果 ----
"abc"
"123"
解釋:
-
第一個(gè)數(shù)字是起始索引;
-
第二個(gè)數(shù)字是您想要多少個(gè)字符。
您還可以使用范圍(range):
實(shí)例:
# 提取從第一個(gè)字符開(kāi)始直到倒數(shù)第二個(gè)字符之間的字符串
string = "abc123"
string[0..-2]
# ---- 輸出結(jié)果 ----
"abc12"
解釋:
-
第一個(gè)數(shù)字仍然是起始索引,但是第二個(gè)索引是結(jié)束索引(含端點(diǎn));
-
-2
代表倒數(shù)第二個(gè)字符,而-1
是最后一個(gè)字符。
如果您想要刪除或替換子字符串,您可以這樣做:
實(shí)例:
# 將從第一個(gè)字符開(kāi)始直到第三個(gè)字符的字符串設(shè)置成空字符串
string = "abc123"
string[0..2] = ""
string
# ---- 輸出結(jié)果 ----
"123"
3.4 如何找出一個(gè)字符串是否包含另一個(gè)字符串
include?
方法:
Tips:在Ruby中,我們約定后面有一個(gè)
?
的方法返回值一定是true
或者false
。
實(shí)例:
# "Today is Saturday"里面是否包含"Saturday"
string = "Today is Saturday"
string.include?("Saturday")
# ---- 輸出結(jié)果 ----
true
解釋:結(jié)果會(huì)返回true
或者false
index
方法:
實(shí)例:
string = "Today is Sunday"
string.index("day")
# ---- 輸出結(jié)果 ----
2
解釋:此方法會(huì)返回查詢的字符串的第一個(gè)字符在被查詢字符串中的索引。
Tips:如果結(jié)果是不包含,會(huì)返回
nil
3.5 判斷兩個(gè)字符串是否相同(不區(qū)分大小寫)
Ruby 字符串比較是要區(qū)分大小寫的,如果比較的兩個(gè)字符串大小不同,則不相等。
對(duì)此我們常用的方法是使方程式的兩邊的字符串都小寫或大寫。
實(shí)例:
# 將兩組字符串都轉(zhuǎn)成大寫或者小寫
lang1 = "ruby"
lang2 = "Ruby"
puts lang1.upcase == lang2.upcase
puts lang1.downcase == lang2.downcase
# ---- 輸出結(jié)果 ----
true
true
Tips :
casecmp?
方法也可以做到這種事,使用較少,不推薦使用
3.6 如何刪除字符串兩側(cè)多余的空格
您可以使用strip
方法刪除多余的空格:
實(shí)例:
# 刪除兩側(cè)多余的空格
extra_space = " Hello World "
extra_space.strip
# ---- 輸出結(jié)果 ----
"Hello World"
經(jīng)驗(yàn):當(dāng)提交表單中包含姓名、郵箱、手機(jī)號(hào)這些參數(shù)的時(shí)候,經(jīng)常會(huì)用到這個(gè)方法。
當(dāng)您只想除去左側(cè)或者右側(cè)的多余空格時(shí),您可以使用lstrip
和 rstrip
。
實(shí)例:
extra_space = " Hello World "
p extra_space.lstrip # 刪除左側(cè)多余的空格
p extra_space.rstrip # 刪除右側(cè)多余的空格
# ---- 輸出結(jié)果 ----
"Hello World "
" Hello World"
3.7 字符串的前綴與后綴
查看字符串是否以特定前綴開(kāi)頭:
實(shí)例:
string = "ruby programming"
string.start_with? "ruby"
# ---- 輸出結(jié)果 ----
true
查看字符串是否以特定后綴結(jié)尾:
實(shí)例:
string = "ruby programming"
string.end_with? "programming"
# ---- 輸出結(jié)果 ----
true
刪除指定前綴:
實(shí)例:
string = "ruby programming"
string.delete_prefix "ruby "
# ---- 輸出結(jié)果 ----
"programming"
刪除指定后綴:
實(shí)例:
string = "ruby programming"
string.delete_suffix " programming"
# ---- 輸出結(jié)果 ----
"ruby"
Tips :
delete_prefix
和delete_suffix
要在Ruby2.5
以上的版本才可以使用
3.8 將字符串轉(zhuǎn)換為字符數(shù)組
使用split
方法可以很容易地將字符串分割成字符數(shù)組:
實(shí)例:
string = "a b c d"
string.split
# ---- 輸出結(jié)果 ----
["a", "b", "c", "d"]
默認(rèn)情況下,split
將使用空格作為分隔符,但是您可以將參數(shù)傳遞給此方法以指定其他分隔符。
實(shí)例:
# 將逗號(hào)作為分隔符
string = "a,b,c,d"
string.split(",")
# ---- 輸出結(jié)果 ----
["a", "b", "c", "d"]
3.9 將數(shù)組轉(zhuǎn)換為字符串
如果您想獲取一個(gè)字符串?dāng)?shù)組并將這些字符串連接成一個(gè)大字符串,則可以使用join
方法。
實(shí)例:
# 將由'a', 'b', 'c'字符組成的數(shù)組合并成一個(gè)字符串
arr = ['a', 'b', 'c']
arr.join
# ---- 輸出結(jié)果 ----
"abc"
也可以通多傳遞參數(shù)指定字符分隔符。
實(shí)例:
arr = ['a', 'b', 'c']
arr.join("-")
# ---- 輸出結(jié)果 ----
"a-b-c"
3.10 將字符串轉(zhuǎn)換為整數(shù)
如果要將"49"
之類的字符串轉(zhuǎn)換為整數(shù)(Integer)的49
,可以使用to_i
方法。
實(shí)例:
"49".to_i
# ---- 輸出結(jié)果 ----
49
注意事項(xiàng):如果您使用不包含數(shù)字的字符串嘗試此操作,則將獲得0。
實(shí)例:
"a".to_i
# ---- 輸出結(jié)果 ----
0
3.11 檢查字符串內(nèi)容是否為一個(gè)整數(shù)
使用正則表達(dá)式(regular expression)來(lái)進(jìn)行判斷:
實(shí)例:
"123".match?(/\A-?\d+\Z/)
"123bb".match?(/\A-?\d+\Z/)
# ---- 輸出結(jié)果 ----
true
false
Tips :
match?
是從ruby2.4以后才引入的,2.4之前的版本可以使用match
來(lái)代替。
解釋:上述正則表達(dá)式的意思為從字符串的開(kāi)頭(\A
)檢查是否有一個(gè)可選的負(fù)號(hào)(-?
,?
代表可選),然后確保中間有一些數(shù)字(\d+
)直到字符串結(jié)尾(\Z
)沒(méi)有其它字符。
3.12 如何附加字符
您可以通過(guò)將字符附加到現(xiàn)有字符串來(lái)從較小的字符串構(gòu)建較大的字符串。這也稱為字符串的串聯(lián)(string concatenation)
我們通過(guò)<<
方法來(lái)實(shí)現(xiàn)這個(gè)操作
實(shí)例:
string = ""
string << "hello"
string << " "
string << "there"
# ---- 輸出結(jié)果 ----
"hello there"
Tips:不要使用
+=
來(lái)進(jìn)行字符串連接,因?yàn)槊看味紩?huì)創(chuàng)建一個(gè)新字符串,這對(duì)性能不利!
3.13 遍歷字符串的字符
有時(shí)您需要對(duì)字符串的每個(gè)字符進(jìn)行操作,這個(gè)時(shí)候就需要遍歷字符串的每個(gè)字符。
第一種方法,您可以使用each_char
方法:
實(shí)例:
# 輸出每一個(gè)字符
"rubyguides".each_char { |ch| puts ch # 這里ch參數(shù)的名稱可以是任意的}
# ---- 輸出結(jié)果 ----
r
u
b
y
g
u
i
d
e
s
另外,您也可以使用chars
方法將字符串轉(zhuǎn)換為字符數(shù)組,對(duì)數(shù)組上每個(gè)對(duì)象進(jìn)行迭代(iterate)。
實(shí)例:
array_of_characters = "rubyguides".chars
# ---- 輸出結(jié)果 ----
["r", "u", "b", "y", "g", "u", "i", "d", "e", "s"]
3.14 字符串轉(zhuǎn)換為大寫或小寫
如果要將字符串所有字符全部大寫,可以使用upcase
方法:
實(shí)例:
"abcd".upcase
# ---- 輸出結(jié)果 ----
"ABCD"
如果要將字符串所有字符全部小寫,可以使用downcase
方法。
實(shí)例:
"ABCD".downcase
# ---- 輸出結(jié)果 ----
"abcd"
3.15 創(chuàng)建多行字符串
第一種方法,使用 Heredoc:
實(shí)例:
b = <<-STRING
aaa
bbb
ccc
STRING
# ---- 輸出結(jié)果 ----
"aaa\nbbb\nccc\n"
另一種,使用%Q
實(shí)例:
a = %Q(aaa
bbb
ccc
)
# ---- 輸出結(jié)果 ----
"aaa\nbbb\nccc\n"
3.16 使用gsub
替換字符串中的文本
如果要替換字符串中的文本,請(qǐng)使用gsub
方法:
實(shí)例:
# 讓我們用“cats”代替“dogs”一詞
string = "We have many dogs"
string.gsub("dogs", "cats")
# ---- 輸出結(jié)果 ----
"We have many cats"
如果要?jiǎng)h除字符串,請(qǐng)使用空字符串作為第二個(gè)參數(shù)。
實(shí)例:
string = "abccc"
string.gsub("c", "")
# ---- 輸出結(jié)果 ----
"ab"
注意事項(xiàng):
-
gsub
方法返回一個(gè)新字符串; -
如果要將更改應(yīng)用于原始字符串,可以使用
gsub!
方法。
gsub
方法還可以將正則表達(dá)式作為參數(shù),因此您可以根據(jù)模式替換而不是確切的單詞。
實(shí)例:
string = "We have 3 cats"
string.gsub(/\d+/, "5")
# ---- 輸出結(jié)果 ----
"We have 5 cats"
解釋:這會(huì)將字符串中的所有數(shù)字(\d+
)替換為數(shù)字5。
我們也可以和塊(block)一同使用
title = "the lord of the rings"
title.gsub(/\w+/) { |word| word.capitalize }
# ---- 輸出結(jié)果 ----
"The Lord Of The Rings"
Tips : 那么
gsub
vssub
有什么區(qū)別呢?
sub
和gsub
使用方法一樣,但是sub
只會(huì)替換第一個(gè)匹配項(xiàng),gsub
會(huì)替換所有項(xiàng)。
3.17 從字符串中刪除最后的\n
或\r
如果您要求用戶輸入某些內(nèi)容(使用Kernel#gets
方法),則在字符串末尾會(huì)有換行符(\n
),這將妨礙您直接比較字符串。
刪除多余的換行符(\n
)的最佳方法是使用chomp
方法。
實(shí)例:
puts "What's your name?"
name = gets
# 輸入名字Alice
# ---- 輸出結(jié)果 ----
"Alice\n"
使用chomp
方法后:
puts "What's your name?"
name = gets.chomp
# 輸入名字Alice
# ---- 輸出結(jié)果 ----
"Alice"
Tips :
chop
和chomp
的區(qū)別
chomp
只會(huì)刪除字符串末尾的\n
或者\r
。
chop
會(huì)刪除字符串末尾最后一個(gè)字符,不管是什么字符。
從 Ruby 2.3 開(kāi)始,chomp
方法采用一個(gè)可選參數(shù),該參數(shù)允許您刪除要?jiǎng)h除的字符。
實(shí)例:
"abcd?".chomp("?")
# ---- 輸出結(jié)果 ----
"abcd"
如果傳入?yún)?shù)的字符不存在,它將返回原始字符串。
3.18 如何更改字符串編碼
字符串按字節(jié)序列存儲(chǔ),根據(jù)它們的編碼,它們變成可以看到的字符。
例如,ASCII 編碼中的數(shù)字 65 表示字母“ A”。
但是,還有更復(fù)雜的編碼,例如 UTF-8,它允許您表示來(lái)自不同語(yǔ)言(中文等)甚至表情符號(hào)的字符。
要獲取字符串的當(dāng)前編碼,可以使用encoding
方法。
實(shí)例:
"abc".encoding
# ---- 輸出結(jié)果 ----
Encoding:UTF-8
從磁盤讀取文件或從網(wǎng)站下載某些數(shù)據(jù)時(shí),可能會(huì)遇到編碼問(wèn)題。
您通常可以通過(guò)轉(zhuǎn)換編碼的方法force_encoding
來(lái)解決該問(wèn)題。
實(shí)例:
"abc".force_encoding("UTF-8")
3.19 字符計(jì)數(shù)
您可以使用count
方法計(jì)算某一個(gè)字符在字符串中出現(xiàn)的次數(shù)。
實(shí)例:
str = "aaab"
str.count("a")
# ---- 輸出結(jié)果 ----
3
str.count("b")
# ---- 輸出結(jié)果 ----
1
4. 小結(jié)
在本章中,您知道了什么字符串,了解如何創(chuàng)建一個(gè)字符串對(duì)象,學(xué)習(xí)了字符串常見(jiàn)的實(shí)例方法以及具體一些應(yīng)用。
打好字符串的基礎(chǔ)后,接下來(lái)讓我們繼續(xù)來(lái)學(xué)習(xí)下一章吧。