1,切片:silce, [ ]-----------------[ ]是silce的別名,所以兩者是完全相同的
操作1:判定字符串中是否含有字串/子模式
string[substring]
string[/pattern/]
string[/pattern/, position] #position之后的子串中是否含有/pattern/
如果存在返回子串/子模式串,否則返回nil
“hello world"["hello"]==="hello"
"hello world"[/.*lo/]==="hello"
"hello world"[/en/]===nil
操作2:使用索引截取子串
string[position] #注意返回的是ASCII碼而不是字符
string[start, length]
string[start..end]
string[start...end]
2,比較:
== #比較字符串是否相等
eql? #??好像沒有區別
<=> #用來比較字符串的大小,大于返回 1,小于返回 -1, 否則返回0
3,字符串的運算
downcase #改變字符串為全部小寫
upcase #改變字符串為全部大寫
swapcase#反寫
capitalize #改變字符串為首字母大寫
* #重復字符串
insert num, string #在num位置插入串string(insert沒有!,因為insert會直接改變原串)
delete(!) string1 (,string2) #刪除string1交string2的字符
gsub find, replace #將串中的find,替換為replace. find可以是正則表達式,replace很顯然不可以。注意:是所有相同的都替換,相當與sed中的s/pattern/string/g
replace string #將字符串替換為string, 這是對象沒有變,只是其中的內容發生了變化。
利用切片來改變字符串(silce!, [ ]=)
"hello"["ello"]= "w" # "hw"
"hello"[1]="wan" # "hwanllo"
“hello"[1..3]= "wrd" #"hwrdo"
"hello"[1...3]= "wr" #"hwrlo"
"hello"[1,3]="wrd" #"hwrdo"
"hello"[/el/]= "wr" #"hwrlo"
chomp(!) 用來摘除字符串末尾的換行符(如果不是換行符返回空)#注意只能是換行符,空格都不行
chop(!)用來摘除字符串末尾的最后一個字符
reverse(!)首尾倒置
split(/pattern/)將字符串分割成數組,分隔符是/pattern/(注意帶!的方法不能用來改變類,所以split沒有?。?br />
字符串長度
string.length
string.size
字符串對齊
string.ljust num, char #用char來填充string,不足num的部分。注意左對齊是右填充。如果字符串長度比char大,忽略
string.rjust num, char
string.center num, char
string.lstring #trim字符串,去除左邊空格
string.rstring
string.strip
..........那么如何去掉所有的空格呢? 很簡單,使用gsub,進行替換
string.next/succ #string+1 不是+1這么簡單。"a".next == "zz"
string1.upto(stringn) #string1, string2 ....stringn
字符串遍歷:
string.each #分割不同項的必須是\n "hello\nworld".each {|e| puts e << ","}===
hello,
world,
"hello world".each{|e| puts e << ","}===
hello world,
string.each_byte #以字節為單位遍歷
求字串的索引位置
string.index substring #正則表達式也可以
正則表達式專用
string.grep /pattern/ #如果不是正則表達式搜索不到任何東西,如果是且匹配返回包含整個字符串的一個數組
string =~ /pattern/ #pattern第一次出現的位置
string !~ /pattern/ #如果沒有找到/pattern返回true(注意!)
uby很強大,可是相關資料少而不詳細。本文是個人學習總結,測試環境是windows xp sp3 + NetBeans6.7.1(JRuby 1.2.0),主要結論來自于互聯網、"Programming Ruby"2e、對于源代碼的分析和實測代碼。
雙引號字符串和單引號字符串
都能表示字符串對象,區別在于雙引號字符串能夠支持更多的轉義字符。下面的代碼在字符串中增加了'符號。
str=‘he'lo’
puts str
顯示結果為he'lo。
單引號僅支持\\ => \ 和 \' => '
下表是ruby中雙引號字符串支持的轉義字符:
分界符
所有不是字母或者數字的單字節字符都可以成為String的分界符。注意,通常他們都是成對出現的,比如<和>,!和!,{和}等。
構造字符串字面量
方法一:
最簡單的使用單引號或者雙引號括起來的字符串,比如"hello"。
方法二:
使用%q配合分界符,%q代表單引號
str=%q!he\lo!
方法三:
使用%Q配合分界符,%Q代表雙引號
str=%Q{he\lo}
方法四:
here document構建字符串,該方法比較適合用于多行字符串的創建。由<<和邊界字符串作為開頭,由邊界字符串作為結尾,比如下列代碼:
str = <<END_OF_STRING1
We are here now,
where are you?
END_OF_STRING1
puts str
輸出結果為:
We are here now,
where are you?
較為復雜的是允許多個邊界字符串對出現。
str = <<END_OF_STRING1,<<END_OF_STRING2
We are here now,
where are you?
END_OF_STRING1
I will leave now,
would you like to go with me?
END_OF_STRING2
puts str
輸出結果為:
We are here now,
where are you?
I will leave now,
would you like to go with me?
字面量與copy-on-write技術
在Java中,如果兩個String對象a和b的值都是"abcdef",如下:
String a="abcdef";
String b="abcdef";
那
么,JVM只會創建一個常量對象"abcdef",讓a和b都指向它。但是在ruby中,采用了智能指針(熟悉c++的朋友清楚)的一個高級技術
copy-on-write,一開始也是共享同一個字符常量,但是一旦之后某個對象(比如b對象)進行了修改操作,則"abcdef"將產生一個副本,b
的修改操作在這個副本上進行。
更詳細的討論請參考http://developer.51cto.com/art/200811/98630.htm。
和Java的一些其他區別
Java的String每次執行修改操作,都不會改變自身,而是創建一個新的String對象,而Ruby每次的修改操作都會修改自身。
計算長度
puts "hello".length
該句輸出5,是字符個數,不要和C函數搞混,C函數經常用0結束字符串,因此長度經常為實際字符個數+1,Ruby中沒有這個習慣。
查找
從左向右查找第一個
index方法有三種重載,分別是:
str.index(substring [, offset]) => fixnum or nil
str.index(fixnum [, offset]) => fixnum or nil
str.index(regexp [, offset]) => fixnum or nil
第二個參數offset是可選參數,不用的話則從索引0的字符開始查找。
puts "hello".index("el") 輸出為1 ,注意這里的'el'也可以。也可以只查一個字符比,如puts "hello".index(101) 輸出為1,這時候第一個參數為'e'的二進制碼。
也可以使用正則表達式進行查找,比如puts "hello".index(/[az]/) 輸出為nil,因為"hello"不包含a或者z。[]是正則表達式的運算符,代表里面的a和z有一個找到即可。
puts "hello".index(/lo/) 這個沒有[]符號,因此是查找子字符串lo,結果為3.
我個人覺得盡量熟練使用正則表達式查找是最好的選擇,既可以完成簡單查找,也可以完成難度查找。不過需要付出不少努力去學習。
下面這個例子puts "hello".index('o', -1) 證明了第二個參數可以為負數,雖然這沒有什么意義,因為功能和為0等價。
如果查找不到,返回nil。
逆向查找(從左向右查找最后一個還是從右向左查找第一個)
str.rindex(substring [, fixnum]) => fixnum or nil
str.rindex(fixnum [, fixnum]) => fixnum or nil
str.rindex(regexp [, fixnum]) => fixnum or nil
第一個參數和index相同,第二個參數是可選,如果不用則默認為字符串尾部。如果為0呢?則從第一個字符開始向右查找。如果為負數呢?這時候很奇怪,居
然能查到。通過看C的實現代碼,發現當fixnum<0時,會執行這個運算:fixnum+=substring.length,然后就能找到。邏
輯上可以理解為當fixnum<0時,將從最右邊開始向左移動abs(fixnum)-1個位置,并作為最后查找范圍,然后開始從左至右進行查找。
字符串最右邊的字符的位置被-1代表。
下面兩行代碼結果都是nil:
puts "hlloe".rindex('e', -2)
puts "hlloe".rindex('e', 3)
下面兩行代碼結果都是1:
puts "hello".rindex('e', -2)
puts "hello".rindex('e', 3)
注意,以上的代碼理解是我個人觀察代碼后的猜測,因為我還不會調試運行ruby的C代碼,所以不一定正確。代碼摘錄如下:(代碼是ruby網站公布的C代
碼,但是我所用的平臺其實NetBeans6.7.1,因此真正代碼應該是Java實現的JRuby1.2.0,這里的C代碼僅供參考)
static VALUE
rb_str_rindex_m(argc, argv, str)
int argc;
VALUE *argv;
VALUE str;
{
VALUE sub;
VALUE position;
long pos;
if (rb_scan_args(argc, argv, "11", ⊂, &position) == 2) {
pos = NUM2LONG(position);
if (pos < 0) {
pos += RSTRING(str)->len;
if (pos < 0) {
if (TYPE(sub) == T_REGEXP) {
rb_backref_set(Qnil);
}
return Qnil;
}
}
if (pos > RSTRING(str)->len) pos = RSTRING(str)->len;
}
else {
pos = RSTRING(str)->len;
}
switch (TYPE(sub)) {
case T_REGEXP:
if (RREGEXP(sub)->len) {
pos = rb_reg_adjust_startpos(sub, str, pos, 1);
pos = rb_reg_search(sub, str, pos, 1);
}
if (pos >= 0) return LONG2NUM(pos);
break;
case T_STRING:
pos = rb_str_rindex(str, sub, pos);
if (pos >= 0) return LONG2NUM(pos);
break;
case T_FIXNUM:
{
int c = FIX2INT(sub);
unsigned char *p = (unsigned char*)RSTRING(str)->ptr + pos;
unsigned char *pbeg = (unsigned char*)RSTRING(str)->ptr;
if (pos == RSTRING(str)->len) {
if (pos == 0) return Qnil;
--p;
}
while (pbeg <= p) {
if (*p == c) return LONG2NUM((char*)p - RSTRING(str)->ptr);
p--;
}
return Qnil;
}
通常我們理解為從右邊開始查找,但是注釋卻表明是從左向右查找,并返回最后一個找到的目標的位置。究竟內幕如何,只能看代碼。
01161 static
long
01162
rb_str_rindex
(str, sub, pos)
01163 VALUE
str, sub;
01164 long
pos;
01165 {
01166 long
len = RSTRING
(sub)->len;
01167 char
*s, *sbeg, *t;
01168
01169
01170 if
(RSTRING
(str)->len < len) return
-1;
01171 if
(RSTRING
(str)->len - pos < len) {
01172 pos = RSTRING
(str)->len - len;
01173 }
01174 sbeg = RSTRING
(str)->ptr;
01175 s = RSTRING
(str)->ptr + pos;
01176 t = RSTRING
(sub)->ptr;
01177 if
(len) {
01178 while
(sbeg <= s) {
01179
if
(
rb_memcmp
(s, t, len) == 0) {
01180
return
s -
RSTRING
(str)->ptr;
01181 }
01182 s--;
01183 }
01184 return
-1;
01185 }
01186 else
{
01187 return
pos;
01188 }
01189 }
通過看代碼,發現s--;因此,是從右向左進行匹配,找到的第一個就返回。寫注釋的人應該槍斃!雖然看上去意思一樣,但是算法的時間復雜度大不一樣。從左到右的查找總是O(n),而從右到左的最壞事件復雜度才是O(n)。
大小寫不區分查找
puts "hello".upcase.index("H"),利用downcase或者upcase全部轉換成小寫或者大寫,然后再查找。
正則表達式匹配查找
operator =~ 將返回匹配的模式開始位置,如果沒有找到則返回nil。
puts "abcde789" =~ /d/
輸出5.
提取子字符串
str="hello"
puts str[0,2]
第一個參數是子字符串首字母的Index,第二個是長度(不能為負數)。
結果為he。
第一個參數可以為負數,會把最右邊的字符作為-1,然后向左增加-1的方式查找起始位置,比如:
str="hello"
puts str[-2,2]
輸出為lo,這種情況我們在rindex方法中已經看到過了。
也可以使用正則表達式進行提取,這真的很強大。
str="hello"
puts str[/h..l/]
輸出為hell。
符號.代表一個字符,兩個.代表兩個字符。兩個/里面的內容就是正則表達式。.*代表可以有無數個字符,比如
str="hello"
puts str[/h.*o/]
輸出為hello。
字符計數
String#count用來計算我們參數中給出的字符集中字符出現的總次數,比如最簡單的情況:
str = "hello,world"
puts str.count "w"
“w" 參數代表的是一個字符結合,里面只有一個字符w,count方法計算出w出現在"hello,world"的次數是1,因此輸出為1。
下面我們的參數里面包含了三個字符:
str = "hello,world"
puts str.count "wld"
輸出為5,w出現1次,l出現3次,d出現1次,正好5次。
也可以傳遞多個參數,每個參數代表一個字符集合,這時候這些字符集合的交集作為count計算的條件:
str = "hello,world"
puts str.count "lo","o"
輸出為2。
str = "hello,world"
puts str.count "lo","o"," "
輸出為0,因為三個集合的交集為空,所以計算結果為0.
注意,如果參數^o,代表o出現的次數不計算。
刪除末尾分隔符
String#chomp方法有一個字符串參數,指定了要在末尾刪除的子字符串。如果不用這個參數,則會將字符串末尾的n,r和rn刪除(如果有的話)。
壓縮重復字符
String#squeeze方法如果不用參數,則會將字符串中的任何連續重復字符變成單一字符,如下:
str = "helllloo"
puts str.squeeze
輸出:helo。
如果傳遞字符串參數,含義同count方法的參數一樣,代表了一個字符集合,則將符合條件(1,在字符集合中出現;2,在字符串中連續出現)的子字符串壓縮成的單一字符
實例代碼如下:
str = "helllloo"
puts str.squeeze('l')
puts str.squeeze('a-l')
puts str.squeeze('lo')
輸出為:
heloo
heloo
helo
參數也可以用a-z方式表示在某個字符集合區間內。
一個很常用的功能是利用squeeze(" ")對字符串內重復的空白字符進行壓縮。
字符串刪除
delete方法
可以接收多個參數,每個參數代表一個字符集合,類似count方法。如果有多個參數,取交集,然后從字符串中刪除所有出現在交集中的字符。
"hello".delete "l","lo" #=> "heo"
"hello".delete "lo" #=> "he"
"hello".delete "aeiou", "^e" #=> "hell"
"hello".delete "ej-m" #=> "ho"
利用sub和gsub
參見后面的sub用法,使用''進行替換即可。
字符串拆分
String#split接收兩個參數,第一個參數總是被作為間隔符來拆分字符串,并且不會出現在結果中。
第一個參數如果是正則表達式的話,如果為空,則每個字符都被拆開,返回一個字符數組。例子代碼如下:
str = "hello"
puts str.split(//)
輸出為:
h
e
l
l
o
如果正則表達式不為空,則根據匹配的情況進行拆分。例子代碼如下:
str = "hello"
puts str.split(/h/)
結果為:
ello
拆分成了兩個數組,第一個為"",第二個為ello,用h進行拆分的。
第一個參數的另一種用法很簡單,只是一個字符串,用于作為間隔符進行拆分,就不舉例子了。我更傾向于使用強大的正則表達式。
第二個參數是一個整數,用于對拆分的結果數組的元素個數進行限制,這個功能有多大用處,我現在到沒有體會,一般情況下不用即可。
大小寫轉換
如前面出現的,利用downcase或者upcase方法即可。
數組操作
使用[],里面填上Index,就可以獲取第Index個元素。
和數值類型的相互轉換
獲取單字節字符的二進制碼
puts ?e
?運算符用于中文是非法的。
字符串迭代
Ruby迭代器的設計不在這里討論,我會專門有一篇文章描述。
each_char
迭代每個字符,下面是示例代碼:
require 'jcode' #NetBeans6.7.1和JRuby1.2.0需要,否則下面代碼找不到方法
"hello".each_char(){ |c| print c,' ' } #()可以不寫
|c| 代表字符串中的當前字符。
each
迭代每個子字符串,如果不傳遞seperator參數,則默認用n作為seperator。
"hellonworld".each { |c| puts c }
輸出為:
hello
world
如果傳遞了有效的字符串作為seperator參數,那么就以這個seperator代替n進行子字符串的迭代:
"hellonworld".each('l') { |s| p s }
輸出為:
"hel"
"l"
"onworl"
"d"
each_byte
用法和each_char類似,不過迭代的對象是char,因此輸出的是二進制數值。
"hellonworld".each_byte { |s| print s," " }
輸出:
104 101 108 108 111 10 119 111 114 108 100
each_line
用法和前面相同,只是用換行符分割子字符串進行迭代:
"hellonworld".each_line do |s|
print s
end
注意,這是另一種寫法,用do/end替換了{/}對。
輸出為:
hello
world
只所以輸出為兩行,是因為第一個子字符串是"hellon"輸出后自動換行。
字符串拼接
使用operator +操作
str1="hello,"
str2="world"
str3=str1+str2
puts str3
輸出為hello,world
使用operator <<操作
str1="hello,"
str2="world"
str1<
puts str1
輸出為hello,world
concat方法
concat方法可以在字符串后面加上一個二進制值為[0,255]的字符,用法如下:
str1="hello,world"
str1.concat(33)#33是!的二進制值
puts str1
輸出為hello,world!
concat也可以接一個object,比如另一個String對象
是否為空
String#empty? 方法 如果為空返回true,否則返回false
字符串比較
operator<=>操作
str1<=>str2
如果str1小于str2,返回-1;
如果str1等于str2,返回0;
如果str1大于str2,返回1。
官方注釋寫反了。
operator==操作
兩個比較對象必須都為String,否則返回false;
如果都是String對象,則調用operator <=> 操作符進行比較,比較結果為0時,返回true,否則返回false
字符串替換
replace方法
和operator = 功能相同,字符串內容的完全替換,沒什么作用。
sub方法
str.sub(pattern, replacement) => new_str
str.sub(pattern) {|match| block } => new_str
在str副本上將找到的第一個匹配字符(串)用replacement替換,并返回。比如:
puts "abcde789".sub(/d/, "000")
輸出為:abcde00089
第二種重載形式允許執行一段代碼,比如:
puts "abcde789".sub(/d/){|c| 'a'}
找到的字符用|c|表示,可以替換成a字符
輸出為:abcdea89
gsub方法
和sub的區別在于所有匹配的地方都會被替換,而不只是第一個。