版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
Ruby技巧Ruby技巧001常值所謂常值(literal),就是用來將數(shù)值、字符串等基本的對象直接寫在腳本中的表示法。數(shù)值
數(shù)值時在程序中可被處理的一種最基本的數(shù)據(jù)形態(tài)。
數(shù)值在處理中,與整數(shù)及小數(shù)有著很大的差異。另外,如果使用標準內(nèi)建的函數(shù)庫,也可以處理矩陣、復數(shù)等整數(shù)、浮點數(shù)以外的其他數(shù)據(jù)形態(tài)。
數(shù)值常數(shù)包括整數(shù)與浮點數(shù)。
整數(shù)
1
-1
1000000000000000
整數(shù)包括固定長整數(shù)(Fixnum)與大數(shù)(Bignum)。Fixnum可表示系統(tǒng)平臺上自然操作的數(shù)值范圍(對32位機器是-230~230-1),而Bignum則表示比此范圍更大的整數(shù)。因為這兩種整數(shù)會視需求自動變換,所以一般在編寫Ruby的腳本時,不需要特別去區(qū)分。
在整數(shù)中,可以依據(jù)個人喜好在每位數(shù)中間加入“_”。在描述位數(shù)較多的數(shù)時,可以更容易閱讀。
1_000_000_000
另外,整數(shù)不僅可以表示十進制數(shù),也可以表示二進制數(shù)、八進制數(shù)、十六進制數(shù)。
sample001-01.rb
#以“0b”開頭的為二進制數(shù)
bin_num=0b01101101
pbin_num
#=>109
#以“0”開頭的為八進制數(shù)
oct_num=0751
poct_num
#=>469
#以“0x”開頭的為十六進制數(shù)
hex_num=0xAF83
phex_num
#=>44931
浮點數(shù)
浮點數(shù)是指使用浮動小數(shù)點表示的數(shù)。浮動小數(shù)點分為“假數(shù)部分”與“指數(shù)部分”,以“假數(shù)X10指數(shù)部分”來表示。如此一來,由大的數(shù)值到小的數(shù)值,都可以用限制的位數(shù)來處理。
在Ruby中,指數(shù)部分與假數(shù)部分是以“假數(shù)e指數(shù)”的形式來表示。例如:1.4*100000會以“1.4e5”來表示,2.0/1000會以“2.0e-3”來表示。
1.2
1.4e5
#1.4X(10的5次方)
2.0e-3
#2.0X(10的-3次方)符號
符號用來表示方法名等,對應內(nèi)部所使用值的對象。符號是以“:”起始的英文與數(shù)字所構(gòu)成(開頭的字符不可使用數(shù)字)。
:sym
:s001
在Ruby1.8中,新增了符號的寫法。
:"symbol123"
#符號“symbol123”
%s[symbol123]
#符號“symbol123”
在過去包含空格符的符號是不可以使用的,但通過新增的寫法,前面那些包含空格符等的符號,也可以使用了。字符串
字符串處理是Ruby拿手的領(lǐng)域之一。為此,在字符串的表示上,導入了如下各種的寫法。
"RubyOnRails學習網(wǎng)"
%q[中國北京]
%Q(ROR學習網(wǎng))
<<"ROR"
紅寶石比珍珠好
HELLO
“''”與“""”這兩種將字符串包住的寫法與其他程序語言是相同的。“''”與“""”的差異有以下兩點。
“""”可使用特殊字符
“""”可在其中展開“#{表達式}”的具體描述語句
所謂特殊字符是指如\n、\t這樣附有“\”的字符。\n表示換行,而\t表示跳格。另外,還有像\x5a這樣的形式是可以用字符的十六進制數(shù)來表示的寫法。
表達式展開是將Ruby的表達式嵌入字符串中的一種寫法。若在“""”的字符串中有“#{表達式}”這樣的字符串,則會執(zhí)行其中的表達式,并將其結(jié)果在字符串中取代“#{表達式}”。
最后,我們使用“<<”的三行寫法,稱為HereDocument。HereDocument將在“<<”的下一行起,一直到某一行開頭為前面第一行中“<<”后所接字符串的行為止的所有文字作為一個字符串。
在HereDocument中也可以展開表達式。正則表達式
正則表達式是一種用來表示字符串樣式(pattern)的寫法,使用在與字符串的比對上。
正則表達式的寫法有兩種:以“//”包住的寫法與以“%r”開頭的寫法。
在使用以“//”包住的寫法時,樣式中不可以直接寫入“\”。我們必須透過“\”來跳脫(Escape)。
/R.*y/
#可相配“R”之后出現(xiàn)任意字符0次以上之后接“y”的字符串
/Ruby\/Python/
#可相配“Ruby/Python”字符串
例如:與“/rubybase/”及“/rubycase/”相配的正則表達式可以用下面的寫法表示。使用“%r”的時候,在“%r”的下一字符表示常值的起始于結(jié)束。
%r|http://www\.5iror\.com/rubybase/|
%r!http://www\.5iror\.com/rubycase/!
當“%r”的下一個字符是“(”、“[”、“{”、“<”的時候,所對應字符的一對表是常值的起始與結(jié)束。
%r[R.*y]
%r{http://www\.5iror\.com/rubybase/index\.htm}
在正則表達式中有“/”字符時,使用“%r”的方法比較方便。數(shù)組
數(shù)組的常值有使用“[]”來包住的寫法以及“%w”的寫法。如果使用“[]”,則以“,”區(qū)分開來的常值就會成為數(shù)組中的一個個元素。
[1,2,3]
如果使用“%w”,則以空格符來分開的常值會變?yōu)閿?shù)組中的元素,如:
%w(abc)
在這種情況下,即使間隔兩個以上的連續(xù)空格符,也只會區(qū)隔出一個元素。
p%w(ab
c)
#=>["a","b","c"]
如果以“%W”來取代“%w”的話,則可以進行表達式的展開。
p%W(ab#{1+1})
#=>["a","b',"2"]哈希(Hash)
哈希的寫法使用“{}”,例如將鍵“a”對應值設為“b”、將鍵“c”對應值設為“d”的哈希,可以使用下列寫法。
hash={"a"=>"b","c"="d"}
也可以使用“,”來替代“=>”。
hash={"a","b","c","d"}
在這種情況下,鍵與其對應值為一對一的映像,哈希中元素的數(shù)量必須為偶數(shù)。輸出指令
要輸出指令的寫法可以使用“ˋˋ”(此處非單撇號(Singleapostrophe),而是反向撇號(Backapostrophe))。以“ˋˋ”括起來的字符串可以作為命令行指令來執(zhí)行,而其結(jié)果會以輸出字符串方式傳回。
ˋechoRubyˋ
#執(zhí)行echo指令
另外也可以使用“%x”的寫法。
%x(echoRuby)
#執(zhí)行echo指令
關(guān)于命令行指令的執(zhí)行與輸出,也請參考以后章節(jié)的“啟動指令”。Ruby技巧002運算符Ruby的運算符有方法類的寫法與非方法類的寫法(與控制結(jié)構(gòu)有關(guān))。一元運算子
一元運算子就是像“!var”這樣置于變量或表達式之前的運算符。
一元運算子除了有正負號之外,也有否定運算符及邏輯運算符。
否定
!
not
~(位反轉(zhuǎn))
正負號
+
-二項運算符
二項運算符是像“1+2”這樣向左右兩方獲取對象來進行運算的運算符。
Ruby的運算符如表1-1所示。大多數(shù)都是二項運算符。雖然處理算術(shù)運算以及比較的運算符較多,但是也有一些如“1...10”這樣用于產(chǎn)生范圍對象的范圍運算符。表1-1Ruby運算符優(yōu)先順位運算符對應的方法意義高
低
::
無
將類別與模塊等連接
[]
[]
對數(shù)組存放
!
無
否定(優(yōu)先度高)
~
~
按位作NOT運算(bitwise-not)
+(單項)
+@
正號
**
**
次方
-(單項)
-@
負號
*
*
乘法運算
/
/
除法運算
%
%
取余數(shù)
+
+
加法
-
-
減法
<<
<<
左移(位運算)
>>
>>
右移(位運算)
&
&
按位作AND運算(bitwise-and)
|
|
按位作OR運算(bitwise-or)
^
^
按位作XOR運算(bitwise-exclusive-or)
<
<
比小
>
>
比大
<=
<=
以下
>=
>=
以上
<=>
<=>
比較大小(航天飛機運算符)
==
==
同值判斷
!=
==的否定
“==”的否定(即“不等于”)
=~
=~
用于正則表達式之比較
!~
=~的否定
“=~”的否定
===
===
在case語句中的同值判斷
&&
無
邏輯積(優(yōu)先度高)
||
無
邏輯和(優(yōu)先度高)
..
無
產(chǎn)生Range對象(包含結(jié)尾)
...
無
產(chǎn)生Range對象(不包含結(jié)尾)
?:
無
條件運算符
=
無
代入值(包含+=、-=等)
not
無
否定(優(yōu)先度低)
and
無
邏輯積(優(yōu)先度低)
or
無
邏輯和(優(yōu)先度低)
其他運算符
其他運算符還包括條件運算符、數(shù)組參考運算符。
條件運算符以
條件?表達式1:表達式2
的形式來使用,與以下if語句表達的意義相同。
if條件then
表達式1
else
表達式2
end
數(shù)組參考運算符[]在當我們要以索引存取如“var[0]”這樣的數(shù)組對象時使用。無法以方法定義的運算符
下列運算符無法作為方法來定義:
::、..、...、?:(條件運算符)、not、and、or、!、&&、||、=Ruby技巧003變量與常數(shù)在Ruby中有5種類型的變量,另外還有常數(shù)。變量的種類是依變量的有效范圍(scope)來分類的。到底是哪一種類型的變量或者是常數(shù),我們可以依據(jù)其名稱的開頭字符來決定。局部變量
局部變量只能由方法、區(qū)塊或者類別的定義語句來存取。其名稱以小寫英文字母或者“_”起始,由英文字母、數(shù)字與“_”組成,如:
1var實例(instance)變量
實例變量僅屬于某個特定的對象,僅能由該對象中的方法來存取。其名稱以“@”開頭,由英文字母、數(shù)字及“_”組成,如:
@ivar類別變量
類別變量屬于特定的類別,可由該類別與其子類別以及其實例(instance)來存取。其名稱以“@@”開頭,由英文字母、數(shù)字與“_”組成,如:
@@cvar全局變量
全局變量不論在程序中的任何一個地方都可以使用。其名稱以“$”開頭,由英文字母、數(shù)字與“_”組成,如:
$gvar虛擬變量
self、true、false、nil、_FILE_、_LINE_這些被稱為虛擬變量。雖然虛擬變量稱為“變量”,但其不可代入,幾乎與常數(shù)沒有差別。它會被稱為“變量”,是因為其名稱所使用的字符種類與局部變量相同。常數(shù)
常數(shù)是設置某定義后,其值就不會變更。其名稱以答謝英文字母起始,由英文字母、數(shù)字及“_”組成,如:
ConstRuby技巧004代入
所謂的代入就是使用“=”,如:
a=3多重代入
如果我們使用下例中的寫法,可以同時將1代入a,將4代入b,將9代入c。這種功能就稱為多重代入。
a,b,c=1,4,9變量定義
一個變量會在其開始代入的同時被定義。如果參考到未被定義的參數(shù)就會產(chǎn)生錯誤。
punknown_var
#=>錯誤
不過,如果是代入值到變量的程序語句被寫到程序中,這樣即使實際上沒有被代入值,此變量也會被定義。如:
iffalse
a=0
#此處并沒有被實行
end
#但是,還是可以參考變量a,會變?yōu)閚il
pa
#=>nil
雖然如此,但除非特別需要,不然的話還是在使用變量前先將值代入較好吧。Ruby技巧005程序語句的分段一般來說,在Ruby中以換行來作為程序語句的分段。
hello()
#一行程序語句
world()
#另一行程序語句
也可以使用“;”來明確地表示程序語句的分段。
hello();world()
這樣的話,可以在一行中寫入多行程序語句。
另外,在程序語句的最后有兩項運算符,或者方法中的參數(shù)中有換行的情況等時,換行就無法作為程序語句的分段。如:
func1("a',"b",
#到此程序語句尚未結(jié)束
"c"+
#到此程序語句仍未結(jié)束
"d")
#至此func1方法的語句才算結(jié)束
上面這段腳本與“func1("a","b","c"+"d")”的程序語句是等價的。Ruby技巧006備注
如果我們要在Ruby腳本中加入一些非腳本的字符串時,就要使用備注的方式。
在Ruby腳本中,以“#”開頭的行會被視為程序的備注。
#備注
obj.some_method()
#這邊“#”后寫的也是備注
另外,以“=begin”開頭的行一直到以“=end”開頭的行,其中間被包住的內(nèi)容,會全部被視為備注來處理。
=begin
備注
備注
=endRuby技巧007真假值與條件判斷真假值
下面說明的條件判斷等內(nèi)容,是以判斷某個值為真或為假來做相應的處理。在Ruby中,僅有false與nil為“假”,除此之外的值都會被視為“真”來處理。條件判斷
條件判斷便是使用if語句、unless語句以及case語句(then可以省略)。
if條件then
我們想進行的處理
end
if條件then
處理1
else
處理2
end
if條件1then
處理1
elsif條件2then
處理2
elsif條件3then
處理3
else
處理4
end
unless條件then
我們想進行的處理
end
if與unless也可以寫在執(zhí)行處理部分的程序語句后。在這種情況下,if與unless又各自可稱為if修飾詞與unless修飾詞。
我們想進行的處理
if條件
我們想進行的處理
unless條件
“我們想進行的處理”也可以通過begin~end包住多行程序語句的方式來書寫,如:
begin
我們想進行的處理
endif條件
begin
我們想進行的處理
endunless條件
而case語句也可以采用如下的使用方式(then可以省略)。
case想比較的表達式
when值1then
處理1
when值2then
處理2
when值3then
處理3
else
處理4
end
想比較的表達式以==運算符(Object#==)與出現(xiàn)的值進行比較后,若與值1的比較為真,則進行處理1;與值2比較為真則進行處理2;與值3的比較為真則進行處理3,若與上列三個值的比較都不為真則進行處理4。無論進行了哪一個處理,處理完后就會跳出case語句。
從Ruby1.8版之后,也可以像下頁用省略條件對象的方式來寫case語句了。
case
when值1then
處理1
when值2then
處理2
when值3then
處理3
else
處理4
end
于是就會個別當值1為真時進行處理1這樣合適的方式來執(zhí)行。
此外,另一種條件判斷的寫法,可以使用“and”、“or”、“&&”、“||”。and與&&是當左邊的部分為真時,便會執(zhí)行右邊的部分;or與||是當左邊的部分為假時,會執(zhí)行右邊的部分。
程序語句and程序語句
程序語句or程序語句
程序語句&&程序語句
程序語句||程序語句
“&&”與“and”,以及“||”與“or”的優(yōu)先級是不同的。詳細說明請參閱“002運算符”中的說明。Ruby技巧008循環(huán)循環(huán)語句與條件判斷語句相似。但與條件判斷語句不同的是循環(huán)語句是到滿足條件為止,會進行多次的循環(huán)處理(do可以省略)。
while條件do
我們想進行重復循環(huán)的處理
end
until條件do
我們想進行重復循環(huán)的處理
end
for變量in對象do
我們想進行重復循環(huán)的處理
end
當我們想進行循環(huán)的語句只有一行的時候,使用while修飾詞與until修飾詞就很方便了。
希望進行循環(huán)的處理while條件
希望進行循環(huán)的處理until條件
在循環(huán)中的語句最少會執(zhí)行一次,也就是在第一次的條件判斷前,就執(zhí)行循環(huán)中的語句,這樣情況可以使用“begin希望進行循環(huán)的處理endwhile條件”的形式來進行循環(huán)控制。
begin
希望進行循環(huán)的處理
endwhile條件
begin
希望進行循環(huán)的處理
enduntil條件
另外,使用下列指令可以在循環(huán)執(zhí)行的過程中中斷循環(huán),也可以回到循環(huán)開頭重新執(zhí)行,如表1-2所示。表1-2中斷循環(huán)的命令命
令內(nèi)容break強制中斷循環(huán)next前進到下一次的循環(huán)執(zhí)行retry重新開始循環(huán)執(zhí)行redo以相同的條件再執(zhí)行一次循環(huán)Ruby技巧009調(diào)用方法調(diào)用方法
調(diào)用方法如下例的方式:
對象.方法名(方法的參數(shù))
沒有參數(shù)或者所有的參數(shù)要設置為系統(tǒng)默認的時候,方法的參數(shù)可以省略。方法的參數(shù)的“()”在不需要特別說明的情況下也可以省略。
例如:要調(diào)用STDOUT對象的puts方法時可以如下面這樣寫:
STDOUT.puts("ruby")
STDOUT.puts"ruby"
#省略“()”的情況
參數(shù)中,可以將數(shù)組以“*”展開后傳入。
a=[1,2,3]
obj.some(*a)
#obj.some(1,2,3)
另外,調(diào)用方法對象的對象稱為receiver。
調(diào)用函數(shù)形式的方法
調(diào)用函數(shù)形式的方法方式如下:
方法名(方法的參數(shù))
在這種情況下,self擔任了receiver的角色。關(guān)于self,請參閱[011]“方法定義”與[013]“類別定義”。
例如,調(diào)用函數(shù)形式的方法puts,可以使用下列方式:
puts("ruby")Ruby技巧010區(qū)塊(block)在Ruby的方法中可以傳入?yún)^(qū)塊。
對象.方法名do|區(qū)塊參數(shù)|
區(qū)塊定義主體
end
也可是使用“{~}”來代替“do~end”。
對象.方法名{|區(qū)塊參數(shù)|
區(qū)塊定義主體
}
也可以將參數(shù)加入到方法中。
對象.方法名(方法的參數(shù))do|區(qū)塊參數(shù)|
區(qū)塊定義主體
end
區(qū)塊參數(shù)用來進行方法定義與區(qū)塊定義主體間的信息交換操作。在帶有區(qū)塊的方法定義中,一旦區(qū)塊被調(diào)用,可將值代入?yún)^(qū)塊參數(shù),而區(qū)塊定義主體則會被執(zhí)行。
下例中所使用的Integer#times是只將receiver的數(shù)進行循環(huán)的一個方法。區(qū)塊參數(shù)會依次被代入0、1、2、3、4,然后執(zhí)行print方法將其輸出。
5.times{|i|
printi
}
#=>01234Ruby技巧011方法(Method)定義使用def語句可以定義方法。
def方法名(參數(shù)列表)
方法定義
end
方法定義會在執(zhí)行時被Ruby解析。
參數(shù)列表的四種參數(shù)僅能以下列的順序來定義。
param
一般的參數(shù)(0個以上)
param=val
附有默認值的參數(shù)(0個以上)
*param
長度可變的參數(shù)(0~1個)
¶m
將區(qū)塊Proc化后接收的參數(shù)(0~1個)
一個使用所有類型參數(shù)的方法定義如下:
defsample_method(name,value,dvalue="sample",*rest,&block)
name與value為一般的參數(shù);dvalue為附有默認值的參數(shù);*rest為長度可變的參數(shù),而&block為被區(qū)塊Proc化后接收的參數(shù)。
附帶區(qū)塊的方法定義
在附帶有區(qū)塊的方法定義的情況下,執(zhí)行被傳遞給方法的區(qū)塊時,使用yield。yield會將接收到的參數(shù)作為區(qū)塊參數(shù)傳遞給區(qū)塊。
defmap_with_index(list)
result=[]
list.each_with_index{|item,idx|
value=yield[item,idx]
result<<value
}
returnresult
end
map_with_index([1,2,3]){|item,idx|item*idx}
#=>[0,2,6]Ruby技巧012限制方法的調(diào)用限制方法的調(diào)用有以下3種方式:
public
將方法定義為可由其他類別定義或者最上層來調(diào)用。
private
只能以省略receiver的形式來調(diào)用方法。
protected
只能在與方法的同一個類別或其子類別中調(diào)用該方法。
當沒有特別指定的時候會預設為public。但是initialize方法除外,initialize方法一般都是private。
在絕大多數(shù)情況下,只會使用public與private。當我們希望在該類別外也可以存取該方法時使用public,不希望時則使用private。Ruby技巧013類別(Class)定義要定義一個類別時,使用class語句。
class類別名
類別的定義
end
也可以定義一個繼承其他類別的子類別。
class子類別(subclass)名<父類別(superclass)名
類別的定義
end
類別也可以使用巢狀結(jié)構(gòu)。
classC1
classC2
:略
end
end
c=c1::c2.new
在Ruby1.8版以后,可以在類別名稱上使用“::”來直接指定巢狀結(jié)構(gòu)中深一層的類別。不過被寫入巢狀結(jié)構(gòu)的類別一定要事先定義好才可以使用。
classC1
:略
end
classC1::C2
deffoo
p"foo"
end
end
C1::C2.new.foo
#=>"foo"
在類別的定義中,self指的是該類別本身。在該類別的實例中,self指的是該實例本身。
classC1
p[self,self.class]
#=>[C1,Class]
deffoo
&nbp;
p[self,self.class]
end
end
C1.new.foo
#=>[#<C1:0x80fea64,C1]Ruby技巧014模塊(Module)定義
在模塊的定義要使用module語句。
module模塊名
模塊定義
end
雖然模塊與類別類似,但其仍有若干差異。模塊與類別的差別如表1-3所示。表1-3模塊與類別的差別
類別模塊引入不可可繼承可不可建立實例(instance)可不可
要引入模塊時應使用include語句。
moduleM1
end
classC
includeM1
#在類別C中引入模塊M1
end
模塊與類別一樣,也可以對模塊使用巢狀結(jié)構(gòu),同時類別與模塊交雜地使用巢狀結(jié)構(gòu)。
moduleM1
moduleM2
classC1
end
end
end
c=M1::M2::C1.new
模塊的定義與類別相同,self是指該模塊對象自身。當該模塊被其他類別引入時,在模塊的方法定義中的self則是指引入該模塊的類別對象本身。Ruby技巧015特殊方法在Ruby中,不僅可以對類別或者模塊定義方法。對于個別的對象,也可以定義該對象僅有的方法。這樣定義的方法稱為特殊方法。
def對象.特殊方法名(參數(shù)列表)
特殊方法的定義
end
此外,想要一次定義多數(shù)個特殊方法時,可以寫成如下形式:
class<<對象
def特殊方法名(參數(shù)列表)
特殊方法的定義
end
end
這邊的“class<<對象~end”形式稱為特殊類別定義,而被這樣定義的類別則稱為“特殊類別”。參考特殊類別定義中的self可以存取特殊類別自身。Ruby技巧016例外處理
Ruby語言也支持例外處理。例如在讀取文件失敗的時候會產(chǎn)生例外,而Ruby便可抓取這樣的例外,并進行相應的處理。
begin
主處理1
rescue
例外類別1=>變量1then
例外處理1
rescue
例外類別2=>變量2then
例外處理2
:
:
rescue例外類別n=>變量nthen
例外類別3
else
主處理2
ensure
主處理3
end
主處理1是進行可能會發(fā)生例外的處理。如果在此處發(fā)生例外的話,會與rescue處制定的例外進行比較。如果發(fā)生的例外是指定的例外類別1或其子類別時,就會執(zhí)行例外處理1。否則就會接著與例外類別2進行比較。接著到例外類別n會重復進行比較的動作。
在省略例外類別的情況下,StandardError類別會被使用。
當沒有發(fā)生例外的時候,主處理2會被執(zhí)行。而主處理3則是不論有沒有發(fā)生例外,最后一定會被執(zhí)行。
另外,也有rescue修飾詞。使用rescue修飾詞,我們可以很簡潔地將例外處理寫為:
主處理rescue例外處理
上面的例子在進行主處理中發(fā)生例外時,就會執(zhí)行例外處理。但這種形式的寫法無法指定rescue例外類別。Ruby技巧017alias與undef賦予別名
Ruby中的方法可以被賦予別名。要對方法賦予別名時使用alias語句。
alias別名原本的名稱
例如要賦予method_old方法一個別名“method_new”時,可以像下面這樣寫:
aliasmethod_newmethod_old
方法名的指定別名也可以使用符號。
alias:method_new:method_old
將方法定義為不可使用
要將已經(jīng)被定義的方法定義為不可使用時,可以使用undef語句。
undef方法名
例如要將some_method方法定義為不可使用時可以使用下列語句:
undefsome_method
undef:some_method
#這樣也可以Ruby技巧018保留字Ruby中有一些名稱不可以被用來當作變量名或者方法名稱,這些名稱叫做“保留字”。在實際使用中如果將這些名稱拿來當作變量或者方法名稱使用的話會發(fā)生錯誤。
Ruby的保留字如表1-4所示。表1-4Ruby的保留字
BEGIN
END
alias
and
begin
break
case
class
def
defined?
do
else
elsif
end
ensure
false
for
if
in
module
next
nil
not
or
redo
rescue
retry
return
self
super
then
true
undef
unless
when
while
yield
_FILE_
_LINE_
Ruby技巧019選擇適當?shù)淖址V祮我柕淖址?”使用在字符串中不包含表達式展開時是很方便的。它是功能最少,且需要跳脫的字符只有“'”以及“\”。在字符串中,包含字符“\”或者包含字符“#”但不想進行表達式展開時使用相當方便。
p'question#{a}'
#=>"question#{a}"
%q
%q字符串在不包含表達式展開的字符串,而且也不包含“'”、“#”時使用相當方便。
p%q(在Ruby中寫入#@ivar的話@ivar中的值會在字符串中被展開)
#=>"在ruby中寫入#@ivar的話@ivar中的值會在字符串中被展開"
""
雙引號字符串“""”是在字符串中包含表達式展開時用來表示字符串的首選。且本書在使用字符串常值時也會將雙引號字符串當作首選。
p"doublequote#{1+1}string"
#=>"doublequote2string"
%Q
%Q字符串是使用在當字符串中含有表達式展開且有“"”的時候。例如將HTML的卷標作為字符串時使用時很方便的。
p%Q[<ahref="">5</a>]
#=>"<ahref=\"\">5</a>"
HereDocument
HereDocument在傳遞多行字符串時是很不錯的選擇。例如要嵌入HTML的標頭、腳注以及原始碼的一部分時使用。
p<<HEREDOC
這是HereDocument
這里也是HereDocument
HEREDOC
#=>"這是HereDocument\n這里也是HereDocument\n"
特別在原始碼等常出現(xiàn)嵌入“\”的字符串時使用單引號HereDocument是最合適的。因為單引號HereDocument會將所有的跳脫字符視為無效。
#有“\”也沒關(guān)系
module_eval(<<'End')
defprintln(arg)
printarg,"\n"
end
end
在處理多字節(jié)字符串時一定要先設置好$KCODE。在此范例中我們假設加載且執(zhí)行$KCODE="UF8"(-Ku)。(譯注:原文中是以處理日文的情況來設置的,而在此使用中文時,本教程預設使用UTF-8環(huán)境。)Ruby技巧020設置默認的文字編碼
在進行字符串處理時,默認的文字編碼是通過全局變量$KCODE來設置的。例如要設置為BIG-5時可以如下例:
$KCODE="NONE"
$KCODE可以設置為下列的值:
"EUC"
:EUC-JP
"SJIS"
:ShiftJIS
"UTF8"
:UTF-8
"NONE"
:無
在設置$KCODE值的時候,只有第一個字符是有意義的,而且英文大小寫的差異會被忽略,所以$KCODE="EUC"也可以寫作$KCODE="euc-jp"或者$KCODE="E"。但是相對于“e”或者“E”來說,“EUC”會是比較好理解的一種寫法,所以我們建議各位盡可能地正確設置$KCODE的值。
另外在腳本中設置$KCODE的情況下,若沒有先加載完畢再開始執(zhí)行的話,是不會產(chǎn)生效果的。例如:在腳本中要直接寫入文字編碼為ShiftJIS的字符串時,雖然在腳本中寫入了$KCODE="SJIS",但卻在該字符串之后,這樣便不會有更換文字編碼的效果。在這種情況下,要在該字段腳本被讀入之前先設置好$KCODE,不然就只能使用Ruby指令的-K參數(shù)。例如可以通過下列方式來設置:
>ruby-Ksscript.rb
關(guān)于-K參數(shù)的使用技巧,也請大家參考[024]“將Ruby腳本做成一般指令”。
另外若事先設置好環(huán)境變量RUBYOPT的話,Ruby會自動地設置好該參數(shù)。
#sh類的UNIXshell
RUBYOPT="-Ks"
exportRUBYOPT
#csh類的UNIXshell
setenvRUBYOPT-Ks
remWindows的命令提示字符(DOSprompt)
setRUBYOPT=-Ks
RUBYOPT的使用方法只有自己使用的話很方便,但是希望讀者不要在發(fā)布出去的程序中強制設置RUBYOPT。Ruby技巧021變換文字編碼JIS、EUC-JP、ShiftJIS、UTF8相互轉(zhuǎn)換
要在JIS(iso-2022-jp)、EUC-JP、ShiftJIS及UTF8之間相互轉(zhuǎn)換的話,使用nkf函數(shù)是最簡單的方法。如果只有指定變換后的文字編碼的話,則會自動推測變換前的文字編碼,然后進行變換。例如下例可將big5碼變換為UTF8碼。
#第二參數(shù)中寫入Big5碼
require"nkf"
pNKF.nkf("-w-m0","\e$B8HAI>k304(;3;{\e(B\r\n")
#=>姑蘇城外寒山寺
NKF.nkf的第一參數(shù)與nkf指令的選項相同。在文字編碼變換時所使用的主要選項如表2-1所示。表2-1文字編碼變換的主要選項
選
項
內(nèi)
容
-j
變換為JIS(iso-2022-jp)
-e
變換為EUS-JP
-s
變換為ShiftJIS
-w
變換為UTF8
-J
將輸入假定為JIS(iso-2022-jp)
-E
將輸入假定為EUC-JP
-S
將輸入假定為ShiftJIS
-W
將輸入假定為UTF8
-x
將日文半角(JISX0201)直接留下,不變換。要變換為ECU-JP的時候使用SS0,變換為JIS時使用ESC
-X
將半角片假名(JISX0201)轉(zhuǎn)換為全角片假名(JISX0208)
--cp932
編碼頁932,也就是與Windows中所用的文字編碼(日文)進行互換。解決了與機種有關(guān)的文字以及部分記號無法正確轉(zhuǎn)換的問題
譯注:在繁體中文版的Windows中是使用950編碼頁,可將此932改為950。
在使用nkf方法的時候,誤了要指定文字編碼外,還應該要指定-m0選項。-m是指定將包含在郵件頭等的MIME字符串進行譯碼的選項,不過很麻煩的是,這個選項默認是開啟的。也就是說,只要偶然出現(xiàn)可以視為MIME字符串的話,其就會自動進行譯碼。所以我們在這里指定-m0來限制這樣的功能。
將半角片假名轉(zhuǎn)換為全角片假名的選項-X,其默認值也是開啟的,所以如果想要保留半角片假名的話,就一定要隨時加上-x選項。
變換更多種的文字編碼
nkf函數(shù)在Ruby1.8.2版以后才可以處理UTF8,因此在Ruby1.8.1版之前要處理UTF-8的話,只能使用iconv函數(shù)。在處理JIS、EUC-JP、ShiftJIS、UTF-8以外的文字編碼時都必須使用iconv函數(shù)。例如,我們將UTF-8的字符串utfstr轉(zhuǎn)換為Big-5碼:
putsIconv.conv("big5","UTF-8",utfstr)
Iconv.conv的第一個參數(shù)是變換后的文字編碼,第二個參數(shù)是變換前的文字編碼,這一點要請您特別注意。
iconv是使用系統(tǒng)的iconv函數(shù),不過在有些系統(tǒng)中不存在iconv函數(shù),而且支持的編碼及其名稱也是非常不規(guī)則。例如把“eucJP”換成“euc-jp”,在Solaris及Tru64UNIX5.1B中就會失敗。在您的能力可以確認的范圍內(nèi),使用下列的名稱可以在大多數(shù)系統(tǒng)上運行。
"ISO-2022-JP"
"SJIS"
"eucJP"
"UTF-8"
譯注:Big-5碼的使用者可以使用“big5”或者“big-5”。
因為大小寫的差別相當重要,所以請務必參照上例中的寫法來編寫。另外,在有些系統(tǒng)平臺上,如果執(zhí)行像“Iconv.conv("eucJp","eucJP",str)”這樣變換前后編碼都相同的話,便會出現(xiàn)錯誤。
我們在這里說明的是conv方法的參數(shù)中文字編碼相同的名稱,所以與變換表的兼容性事沒有關(guān)系的?;旧希斚到y(tǒng)不同的話,可以說變換表是沒有兼容性的。
最后,雖然不是標準內(nèi)建的函數(shù),不過在UTF-8的變換上還可以使用uconv函數(shù)。uconv函數(shù)僅是以Ruby的擴充函數(shù)來完成的,所以在結(jié)果兼容性很重要的情況下,或許使用uconv會比較好。
Uconv.u8toeuc(str)
#UTF-8
->EUC-JP
Uconv.u8tosjis(str)
#UTF-8
->ShiftJIS
Uconv.euctou8(str)
#EUC-JP
->UTF-8
Uconv.sjistou8(str)
#UTF-8
->UTF-8
譯注:uconv目前僅支持UTF-8、EUC-JP、JIS、ShiftJIS、CP932、UTF-16,尚未支持中文編碼。
說明:在處理多字節(jié)字符串的時候,一定要事先設置$KCODE。在這項技巧中,我們假設的環(huán)境是設置$KCODE="UTF8"(-Ku)后,再進行加載、執(zhí)行。
nkf函數(shù)只有在Ruby1.8.2版之后才支持UTF-8。
iconv函數(shù)是在Ruby1.8版之后為標準內(nèi)部函數(shù)庫。
要取得非標準內(nèi)部函數(shù)庫的話,可以由下列位置取得。
/list.rhtml?name=uconvRuby技巧022推測文字編碼
要推測字符串的文字編碼,可以使用nfk函數(shù)的NFK.guess。
require"nfk"
str="這是中文字符串"
NFK.guess(str)
guess方法會傳回結(jié)果NFK::JIS、NFK::EUC等常數(shù)(數(shù)值)。想要通過文字編碼名得到推測結(jié)果的話,可以如下例所示:
require"nkf"
CODE_TO_NAME=Hash.new("ASCII")
CODE_TO_NAME[NFK::JIS]
="JIS"
CODE_TO_NAME[NFK::EUC]
="EUC"
CODE_TO_NAME[NFK::SJIS]
="SJIS"
CODE_TO_NAME[NFK::BINARY]="BINARY"
CODE_TO_NAME[NFK::UTF8]
="UTF8"
ifNFK.const_defined?(:UTF8)
defguess_encoding(str)
CODE_TO_NAME[NFK.guess(str)]
end
因為原本就是“推測”的,所以guess方法也會有推測錯誤的情況。基本上,請大家要考慮到在腳本中不得不推測文字編碼會發(fā)生錯誤的情況。
此外,NFK.guess方法如果不是Ruby1.8.2以后的版本,則沒有辦法推測UTF-8編碼。在Ruby1.8.1之前要推測字符串編碼是否為UTF-8的話,要通過iconv函數(shù)將字符串變換到目的字符串編碼。
sample022-03.rb
require"iconv"
require"nfk"
defguess_encoding2(str)
Iconv.iconv("UTF-8","UTF-8",str)
"UTF8"
rescueIconv::Error
guess_encoding(str)
#UTF-8以外利用nfk來推測
endRuby技巧023復制字符串
要復制字符串的話,可以利用String#dup或String#clone。
str="Thisisastring"
pstr.dup
#=>"Thisisastring"
pstr.clone
#=>"Thisisastring"
pstr.object_id
#=>538155386
pstr.dup.object_id#=>538155366
dup方法只會復制字符串的內(nèi)容。clone除了復制字符串的內(nèi)容,同時也繼承了特殊方法、污染(taint)、凍結(jié)(freeze)等信息。
一般來說,使用dup方法已經(jīng)足夠了。Ruby技巧024重復字符串
若要建立一個重復某個字符串的字符串,可以使用運算符“*”(String#*)。
p"foo"*5
#=>"foofoofoofoofoo"
p
"郁"*3
#=>"郁郁郁"
另外,數(shù)值的“*”運算符放在左邊或者右邊其結(jié)果都是相同的,但是在字符串中就不可以左右交換來放。一定要字符串放在運算符的左邊,整數(shù)放在運算符的右邊。反過來的話,就會發(fā)生像下例中的例外。
p5*"foo"
#=>TypeError:Stringcan'tbecoercedintoFixnum
說明:處理多字節(jié)字符串時必須要事先設置#KCODE。在此例中使用中文,就無須特別加上$KCODE的設置,但若是處理如UTF-8的字符串時,就必須先設置如$KCODE="UTF8"。Ruby技巧025取得字符串長度
在說“字符串長度”時,一般有兩個意義:字節(jié)(Byte)數(shù)與文字數(shù)。
取得位數(shù)
字符串的位數(shù)可以通過String#length或String#size來取得。這兩個方法雖然名稱不同,但是其操作是相同的。
p"Thisisastring.".length
#=>17
p"ThisisaString.".size
#=>17
取得文字數(shù)
字符串的文字數(shù)可以通過下列方式取得:
p"字符串長度".split(//).size
#=>5
“split(//)”是String#split的特殊用法,將字符串分割至字符串數(shù)組中。數(shù)出該數(shù)組的長度也就是文字的長度。不過如果沒有事先適當?shù)卦O置好$KCODE的話,split可能會無法順利運作。
說明:在處理多字節(jié)字符串時,一定要事先設置$KCODE。在這項技巧中,我們假設的環(huán)境是設置$KCODE="UTF8"(-Ku)后,再進行加載、執(zhí)行。Ruby技巧026查找字符串
查詢是否含有樣式(Pattern)
如果只要查詢字符串中是否包含樣式的時候,可以使用=~運算符(Regexp#=~)
#是否包含有空格符或者Tab?
p(/[\t]/=~"ac")
#=>1
p(/[\t]/=~"abc")
#=>nil
查詢樣式第一次出現(xiàn)的字節(jié)位置
如果想要知道指定樣式第一次出現(xiàn)的字節(jié)位置的話,可以使用String#index
p"xxxabcabcabcxxx".index(/abc/)
#=>3
p"xxxabcabcabcxxx".index(".")
#=>nil
p"xxxxxx".index(".")
#=>3
查詢樣式最后出現(xiàn)的字節(jié)位置
如果想要知道指定樣式最后一次出現(xiàn)的字節(jié)位置的話,可以使用String#rindex。
p"xxxabcabcabcxxx".rindex(/abc/)
#=>
9
p"xxxabcabcabcxxx".rindex(".")
#=>nil
p"xxxxxx".rindex(".")
#=>11
取得匹配的詳細信息
使用Regexp#match的話,可以取得關(guān)于匹配的詳細信息(MatchData對象)。我們可以由此對象中取得關(guān)于匹配部分的開頭、結(jié)尾的字節(jié)位置,以及匹配部分的字符串等各種信息。String#match也可以取得與Regexp#match同樣的結(jié)果。
m=/abc/.match("xxxabcabcabcxxx")
pm.begin(0)
#=>3
pm.end(0)
#=>6
pm[0]
#=>"abc"
pm.post_match
#=>"abcabcxxx"
m="xxxabcabcabcxxx".match(/abc/)
pm.begin(0)
#=>3
pm.end(0)
#=>6
pm[0]
#=>"abc"
pm.post_match
#=>"abcabcxxx"
在一個字符串中匹配所有的候選
到目前為止介紹的方法都只能匹配到在字符串中數(shù)個可匹配的開頭(或者結(jié)尾)部分的其中一個,不過實際上我們也可以讓程序去匹配所有符合的部分。這就要使用String#scan方法。
#匹配所有注音符號
str="ㄅ\naadㄆㄇe\neㄈ0\n0aㄍ\niiㄚ\n"
str.scan(/[ㄅ-ㄜ]+/){|s|
putss
}
#=>ㄅ
#=>ㄆㄇ
#=>ㄈ
#=>ㄍ
#=>ㄚ
String#scan在正則表達式中加入“()”的話,則會改變其動作,請讀者要注意。
只處理包含有樣式的行
在一個字符串中包含多行的時候,若要重復處理包含樣式的行,則可以使用String#grep(Enumerable#grep)。
#只處理包含有“快”或“樂”的行
str="快\naad好吃e\ne
樂0\n0a哈\nii好\n"
str.grep([快樂]){|line|
pline
}
#=>"快\n"
#=>"e樂0\n"
也就是說,下面兩個方式是一樣的。
str.gerp(re){|line|
各行的處理
}
str.each{
ifre=~line
各行的處理
end
}
說明:Ruby1.6版中String#scan的參數(shù)在兩個以上字符串的情況下,會變換為Regexp對象之后進行查找,而在Ruby1.8版之后就會直接以該字符串來進行搜索。因此在有Meta字符(“.”及“*”等)的情況下,其運作會有所不同。要避開這個規(guī)格的問題,只要一直都使用正則表達式的參數(shù)就可以解決。
String#match在Ruby1.8版之后才被定義。
在處理多字節(jié)字符串的時候,一定要實現(xiàn)設置$KCODE。在這項技巧下,我們假設的環(huán)境是設置$KCODE="UTF8"(-Ku)后,再進行加載、執(zhí)行。Ruby技巧027查詢正則表達式是否匹配字符串的開頭/結(jié)尾Ruby的正則表達式是以\A表示“字符串開頭”,以\z(小寫的z,請注意)表示“字符串結(jié)尾”。
p(/\A5/=~"5iror")
#=>0
p(/\Ao/=~"5iror")
#=>nil
p(/r\z/=~"5iror")
#=>4
p(/5\z/=~"5iror")
#=>nil
雖然一般我們看到匹配“字符串開頭”、“字符串結(jié)尾”大多使用“^”、“$”,不過這也是有點差異的。因為“^”是指“行的開頭”,而不是“字符串的開頭”。“$”是指“行尾”,而不是“字符串的結(jié)尾”。而且使用大寫Z的“\Z”是“字符串中的最后行尾”。
p"abc\ndef\nghi\n".slice(/..s/m)
#=>"bc"
p"abc\ndef\nghi\n".slice(/..\Z/m)
#=>"hi"
p"abc\ndef\nghi\n".slice(/..\z/m)
#=>"i\n"
只有在使用sub方法的時候,匹配“字符串開頭”與“字符串結(jié)尾”才使用“^”與“$”,這與使用gsub方法并不相同。請明確區(qū)別。
說明:在處理多字節(jié)字符串的時候,一定要事先設置$KCODE。在這項技巧中,我們假設的環(huán)境是設置$KCODE="UTF8"(-Ku)后,才進行加載、執(zhí)行。Ruby技巧028匹配單字
查詢是否包含單字
首先,我們考慮當查詢是否包含特殊單字的情況。例如我們想要查找“spec”,但不希望匹配到“specification”。在這種情況下,可以使用表示單字邊界的正則表達式\b。
p/\bspec\b/=~"Rubyspec"
#=>5
p/\bspec\b/=~"Rubyspecification"
#=>nil
嚴謹?shù)卣f,正則表達式的\b是匹配到\w(一個英文字母或數(shù)字)與\W(不與\w匹配的一個字符)的間隙。
不過,將$KCODE設置為"UTF8"的話,UTF-8的中文字也可以匹配\w,所以\b就變得無法匹配中文與英文字母的間隙了。
p/紅寶石\b/=~"紅寶石abc"
#=>nil
這好像是理所當然,不過又有點背離常理。
根據(jù)正則表達式引擎,可以使用表示“單字的開始”、“單字的結(jié)尾”的“\<”及“\>”,但是這兩樣不存在于Ruby的正則表達式引擎中。以前原本是存在的,不過后來因為“記號如果以\來跳脫的話,就會匹配到字符本身”的理由,在統(tǒng)一基準之前就被刪掉了。
匹配單字
接著,我們來考慮匹配一般的“單字”。因為“單字”的意義并不一定,所以請讀者先想看看,想要怎樣的“單字”。例如說像下面的定義范例。
(1)匹配Ruby的正則表達式\w的連續(xù)字符
->可以表示為/\w+/。
p"
Thisis\ta2pen.".scan(/w+/)
#=>["This","is","a","2pen"]
(2)連續(xù)的英文字母
->可以表示為/[a-z]+/i。
p"
Thisis\ta2pen.".scan(/[a-z]+/i)
#=>["This","is","a","pen"]
(3)連續(xù)的非空格字符。必須以半角空格符來切分。
->可以通過String#slipt(nil)來取得。
p"
Thisis\ta2pen".split(nil)
#=>["This","is","a","2pen."]
如果不只要匹配,還要取出匹配部分的字符串的話,可以通過正則表達式并使用String#slice或String#scan方法。詳細內(nèi)容請參考[042]“取出正則表達式匹配的部分”。
說明:在處理多字節(jié)字符串的時候,一定要事先設置$KCODE。在這項技巧中,我們假設的環(huán)境是設置$KCODE="UTF8"(-Ku)后,再進行加載、執(zhí)行。Ruby技巧029以特定的文字編碼來進行正則表達式匹配
要處理多字節(jié)字符串時,設置$KCODE是基本工作,不過根據(jù)狀況的不同,有時也無法設置$KCODE。比如說,在應用程序中設置$KCODE="NONE"時,我們只想要以函數(shù)中的一部分來處理UTF-8字符串。
在這種情況下,我們要在正則表達式中加入文字編碼選項來進行處理。加上文字編碼選項后,就與$KCODE無關(guān),可以以同一個文字編碼來進行正則表達式的匹配,如下面的腳本所示:
#正則表達式與字符串時通過BIG-5來輸入的($KCODE="NONE")
p(/梣/
=~"博碩")
#=>0
p(/梣/n=~"博碩")
#=>nil
BIG-5的“梣”為"\325\272",而“博碩”為"\345\215\232\347\242\251",所以在沒有設置$KCODE及文字編碼的情況下,正則表達式會在不正確的位置匹配到字符串。但是后者的編碼加上文字編碼,可以清楚知道多字節(jié)文字的區(qū)分處,所以可以正確地判斷匹配的失敗。
目前,可以使用的文字編碼有下列四種,如表2-2所示。其與$KCODE的第一個字符相同,讀者可以將其記下。表2-2文字編碼
選
項
內(nèi)
容
n
無法處理多字節(jié)字符串
e
EUC-JP
s
ShiftJIS
u
UTF8
在處理多個文字編碼的情況下,不要直接在腳本中寫入EUC或者ShiftJIS的字符串常值比較好。例如ShiftJIS的“表”等如果不設置$KCODE="SJIS"的話是無法解析的,而如果設置$KCODE="SJIS"后,又可能會在其他的地方發(fā)生問題。此時使用跳脫字符的序列(EscapeSequence)來寫入常值的話,就與$KCODE無關(guān),而可以在正則表達式中嵌入多字節(jié)文字。
#BIG-5的“/程序語言/”
/#{"\265{\246\241\273y\250\245"}/n
#UTF8的“/程序語言/”
/#{"\347\250\213\345\274\217\350\252\236\350\250\200"}/u
在這種情況下,一定要使用表達式展開(#{表達式})。如果直接寫上/\347\250\213\345\274\217\350\252\236\350\250\200/u,正則表達式的選項u就不會產(chǎn)生任何效果了。
注:本系列技巧的有關(guān)文字編碼的問題均在處理UTF-8編碼上,因為是原本Ruby就支持的文字編碼,所以不會發(fā)生問題。而在處理中文的BIG-5編碼上,因為Ruby本身并沒有支持BIG-5編碼的處理,所以在部分情況下會發(fā)生問題。
在目前來說,可能會使用到BIG-5編碼的用戶,大多數(shù)應該都是使用MicrosoftWindows操作系統(tǒng)的用戶,就測試的結(jié)果而言,要在Windows操作系統(tǒng)上正確顯示BIG-5編碼的話,大多數(shù)的情況下無須特別設置$KCODE。但若發(fā)生無法正常顯示變量內(nèi)容,或者無法正常處理中文字符的情況下,可以試著將$KCODE設為"E"(EUC-JP),則可以正常處理。但此方法算是較困難的方法,且不保證在所有BIG-5碼的處理中都可以正常運作。
就目前來說,要以Ruby來正常處理中文字符的話,建議大家采用UTF-8編碼會是比較好的選擇。Ruby技巧030在正則表達式“.”中匹配\n在正則表達式中加入m選項。
p(/./=~"\n")
#=>nil(因為沒有m選項,所以.不會匹配\n)
p(/./m=~"\n")
#=>0(加上m選項,所以.可以匹配\n)
加上m選項之后,“.”可以匹配任何字符。
對應多字節(jié)文字時的正則表達式“.”
在對應多字節(jié)文字為有效的時候,必須要特別注意。在文字中間切開的多字節(jié)文字,無論如何都無法與“.”匹配。
p(/./u
=~"博"[0,1])
#=>nil
p(/./um=~"博"[0,1])
#=>nil
而反過來說,在$KCODE="NONE"(或者加上n選項)中加入m選項的話,“.”就可以匹配到所有的字符。
defmatch_all_char?(re)
(0..255).map{|byte|byte.chr}.all?{|ch|re=~ch}
end
pmatch_all_char?(/./)
#=>false
pmatch_all_char?(/./um)
#=>false
pmatch_all_char?(/./nm)
#=>trueRuby技巧031從上次匹配的部分開始繼續(xù)匹配
在進行過一次正則表達式匹配后,要在匹配的部分后面繼續(xù)匹配的話,只要將已經(jīng)匹配的部分字符串刪除就可以了。我們可以通過$'或MatchData#post_match來取得“匹配部分之后”的字符串。
str="abcdefghijkl"
pstr.slice(/\w+/)
#=>"abc"
str=$'
pstr
#=>
#=>"defghijkl"
pstr.slice(/\w+/)
#=>"def"
若使用循環(huán)的話,就如同下例所示。
str="abcdefghijkl"
result=[]
whiletoken=str.slice(/\w+/)
result.pushtoken
str=$'
end
presult
#=>["abc","def","ghi","jkl"]
strscan函數(shù)就好像是為了“從上次匹配的部分之后繼續(xù)進行匹配”而特制的函數(shù)。請看下面的例子。
require"strscan"
scanner=StringScanner.new("abcdefghijkl")
result=[]
untilscanner.eos?
result.pushscanner.scan(/\w+/)
end
presult
#=>["abc","","def","","ghi","","jkl"]
您可以將StringScanner#scan想成一個例子中同時進行slice與str=$'的一個方法。與string#slice和$'的使用場合的不同在于,這個方法只會匹配字符串的開頭。因此我們必須要在正則表達式上加\W+(一個以上\w以外的字符),使其可以順利地scan下去。
最后,我們在此簡單說明StringScanner類別與其他方法。StringScanner#getch會傳回開頭的頭一個文字(反映$KCODE)。Stringcanner#eos?會掃描到字符串結(jié)尾為止,若到字符串結(jié)尾則傳回true。
StringScanner類別中還有其他許多的方法,不過因為在此無法完全寫入,所以其他的詳細內(nèi)容還請大家參閱其參考手冊。Ruby技巧032匹配單字
計算文字出現(xiàn)的次數(shù)
要計算特定文字在一個字符串中出現(xiàn)的次數(shù)可以使用String#count方法,不過這個方法并不支持多字節(jié)文字。
p"a\nb\nccc\nd\n".count("\n")
#=>4
計算多字節(jié)文字出現(xiàn)的次數(shù)
要計算特定的多字節(jié)文字在一個字符串中出現(xiàn)的次數(shù)可以使用String#scan方法。以scan方法來建立一個只含有匹配樣式文字的數(shù)組,然后再以Array#length來求得數(shù)組的大小,也就是該文字出現(xiàn)的次數(shù)了。
#計算“博”“文”出現(xiàn)次數(shù)的總和
p"博博博博文文文博文視點".scan(/[博文]/).length
#=>9
當對象字符串大小接近無窮大的時候,通過scan方法來建立數(shù)組的成本會出現(xiàn)問題,可以使用下列方法不建立中間數(shù)組也可以計算。
count=0
"博博博博文文文博文視點".scan(/[博文]/){
count+=1
}
pcount#=>9
計算字符串的出現(xiàn)次數(shù)
如果我們不是要計算文字數(shù)而是要計算字符串的出現(xiàn)次數(shù)的話,也是使用String#scan。這個方法可以支持多字節(jié)字符串。
p"博博博博文文文博文視點".scan(/博文/).length
#=>2
說明:如果不想建立中間數(shù)組的話,可以如上所示使用區(qū)塊的方式來計算。
在處理多字節(jié)字符串的時候,一定要事先設置$KCODE。在這項技巧中,我們假設的環(huán)境是設置$KCODE="UTF8"(-Ku)后,再進行加載、執(zhí)行。Ruby技巧033計算字符的出現(xiàn)頻率
使用下列方法,可以計算出在一個字符串str中各個字符出現(xiàn)的頻率。
def
char_stat(str)
table=Hash.new(0)
str.scan(/./m){|ch|
table[ch]+=1
}
table.to_a.sort_by{|char,count|-count}
end
這個方法可以計算各個字符在字符串中出現(xiàn)的次數(shù),然后將結(jié)果以從多到少的順序傳回。傳回值為“[字符,出現(xiàn)次數(shù)]”這樣的數(shù)組。使用方法參考下例。
char_stat("3.14159265357919").each{|char,count|
puts"#{char.inspect}:#{count}"
}
如下例的作法,可以算出各個字符在字符串中所占的比例。
str="3.14159265357919"
char_stat(str).each{|char,count|
puts"#{char.inspect}:#{count*100/str.length}%"
}
試著以這個方法來處理所遇Ruby1.8的標準函數(shù)文件的話,可以得到的前幾名如下所示:
"":22%
"e":7%
"t":4%Ruby技巧034比較字符串
如果只是想要比較內(nèi)容知道其內(nèi)容是否相等的話,使用“==”是比較恰當?shù)摹?/p>
p"小青蛙"=="小青蛙"
#=>true
p"小青蛙"=="蛙"
#=>false
若不區(qū)分英文大小寫來進行比較的話,可以將兩字符串都以String#downcase變?yōu)樾懞?,再以?=”進行比較。
p"Content".downcase=="CONTENT".downcase
#=>true
如果想要以文字編碼順序來知道哪一個編碼值較小的話,可以在字符串間使用比較運算符<、<=、>、>=等進行比較。
p"abc">"xyz"
#=>false
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 貴金屬首飾檢驗員風險評估與管理測試考核試卷含答案
- 海水捕撈工成果知識考核試卷含答案
- 2025年結(jié)核病的自查報告
- 銅粉購銷合同范本
- 廣安市全肥養(yǎng)殖家庭農(nóng)場生豬養(yǎng)殖項目報告書
- 分銷商合同協(xié)議書
- 異地簽協(xié)議書合同
- 房產(chǎn)合同補償協(xié)議
- 沖床購銷合同范本
- 分銷協(xié)議銷售合同
- GB/T 19362.1-2003龍門銑床檢驗條件精度檢驗第1部分:固定式龍門銑床
- AQ安全資料管理規(guī)程(北京市)課件
- 人飲工程監(jiān)理細則樣本
- 立體車庫技術(shù)參數(shù)及要求
- 青春期教育 完整版課件
- 介電性能精品課件
- 初中數(shù)學滬科版九下 隨機事件部優(yōu)課件
- DB11T 716-2019 穿越既有道路設施工程技術(shù)要求
- 【瘋狂動物城】超精致卡通電影主題通用模板
- 萬用表的使用(課堂PPT)課件
- a表A.6.1 變電站建筑工程設計強制性條文參考引用表
評論
0/150
提交評論