Ruby字符串(1):String基本用法

String字符串

字符串由String類提供,除了直接使用單雙引號或其它字面量建立字符串,也可使用String.new()方法來建立。正則表達式

a = "hello"
b = String.new("world")

Ruby中的字符串是可變對象數組

字符串的鏈接

直接鏈接便可:ruby

>> "a""b"
=> "ab"

>> "a" "b"
=> "ab"

>> "a"    "b"
=> "ab"

單雙引號

這和Perl同樣,和Shell也相似。單引號是強引用,雙引號是弱引用。性能

雙引號的一個特性是支持表達式、變量內插,使用#符號便可。在Ruby中,#前綴能夠看做是一種對某對象的引用、調用之義。例如:編碼

  • 內插全局變量#$var
  • 內插實例變量#@var
  • 內插類變量#@@var
  • 可是對於普通的不帶前綴符號的局部變量或表達式,爲了不歧義,一般在#後加上{}。例如#{name}#{3+4}#{func("hello")}

因此,在雙引號中若是#字符後面的是$ @ @@ {,須要對#轉義,其它時候,不須要對它轉義。.net

格式化字符串內插

Ruby顯然也是支持printf、sprintf的,可是Ruby除了表達式或變量內插,還支持格式化字符串內插。code

sprintf "pi is about %.4f",Math::PI
=> "pi is about 3.1416"

"pi is about %.4f" % Math::PI # 單個格式化字符串
=> "pi is about 3.1416"

"%s: %f" % ["pi", Math::PI]  # 多個格式化字符串
=> "pi: 3.141593"

"xiaomage = %{age}" % {:age => "23"}
=> "xiaomage = 23"

正如上面的示例,須要進行格式化的字符使用%標識,並使用%鏈接字符串和待替換的值。若是要內插多個字符串,則值部分使用中括號包圍(即放進數組)或放進hash。regexp

%q和%Q和%

這和Perl裏的q() qq()是同樣的,也是分別充當單引號、雙引號的角色。%q()被解析成單引號,單個%%Q被解析成雙引號。對象

%q %Q後面的()是引號的起始、終止定界符,定界符能夠替換成其餘成對或相同的符號。例如,下面是等價的:blog

# 如下等價,內部的單引號不須要反斜線轉義
%q(hello'world)
%q[hello'world]
%q{hello'world}
%q!hello'world!
%q#hello'world#

# 如下等價
%Q(hello'world)
%Q[hello'world]
%{hello'world}    # 單個%是同樣的
%!hello'world!
%#hello'world#

若是使用的是成對的定界符,那麼在定界符內只要合理的配對,就能夠包含定界符字面符號。例如:

%Q(hello(hello world)world)
%<<book>Ruby</book>>
%((1+(2*3)) = #{(1+(2*3))})
%(A mismatched paren \( must be escaped) # 不配對的括號須要轉義

關於字符串的可變性

對於Ruby來講,字符串是可變的。因此,沒法使用單個對象來引用內容相同的兩個字符串,若是能引用的話,其中一個修改了就表示另外一個字符串也會修改,但這已經表示同一個對象了。

因此,只要Ruby遇到一個字符串,都會新建立一個字符串對象。這意味着,若是在一個循環中使用了字符串常量,那麼這個常量字符串對象也會在每次循環過程當中新建立,而這是能夠避免的消耗性能的一種方式。

>> 10.times {puts "test".object_id}
12046480
12046340
12046280
12046220
12046160
12046080
12046000
12045880
12045780
12045680

單字符

使用一個問號做爲下一個字符的前綴,這個字符將稱爲字符字面量。例如:

?A   # 表明一個大寫字母A
??   # 表明一個問號
?"   # 表明一個雙引號

在Ruby1.8及以前的版本,這是一個單字符序列,會轉換成ASCII碼存放,在Ruby 1.9以後,單字符等價於只有一個字符的字符串

>> ?A == 'A'
=> true

擴展字符串:+ * <<

想要鏈接兩個字符串,直接不使用任何鏈接符或使用"+"就能夠。但注意,它們不會自動將其它類型轉換成字符串類型,須要手動調用to_s方法來轉換。

>> "A""B"
=> "AB"

>> "A"+"B"
=> "AB"

>> "A"2    # SyntaxError: 
>> "A"+2   # TypeError

>> "A"+2.to_s
=> "A2"

可以使用"<<"將多個字符串追加到某個字符串的尾部,它一樣不會自動轉換成字符串。這時候字符串就像是一個字符數組同樣,但須要知道,Ruby字符串不是字符數組,只是實現了一些好用的操做字符串的方法:

>> "abc" << "hello" <<"world"
=> "abchelloworld"

<<能夠直接追加整數,整數被看成ASCII或其它編碼字符進行轉換,使得追加到字符串裏的是字符。

>> "xyz" << 65
=> "xyzA"

只是須要注意的是,使用+或直接相連擴展字符串的方式時會自動建立一個新的字符串對象,原始字符串不變,也就是說在獲得擴展的結果前拷貝了一些數據進行建立新字符串對象。而使用<<的方式,由於修改的是字符數組,因此是原地修改的

>> a="xyz"
=> "xyz"

>> a + "XYZ"
=> "xyzXYZ"
>> a      # a沒有變
=> "xyz"

>> a << "XYZ"
=> "xyzXYZ"
>> a          # a已經變了
=> "xyzXYZ"

*號重複字符串N次。因而,能夠簡單地寫出等長的萬惡分割線。例如:

>> "ab" * 3
=> "ababab"

>> '-' * 40
=> "----------------------------------------"

字符串的索引屬性

字符串可變、可索引子串、設置子串、插入子串、刪除子串等等。

字符串[]()搜索和賦值

經過[]能夠對字符串進行搜索和賦值,賦值時是原處修改字符串的。索引方式有多種,且支持負數索引號。

# 1.根據索引,搜索或賦值單元素
str[index] → new_str or nil
str[index] = new_str

# 2.根據索引和給定長度,搜索或賦值0或多個元素
str[start, length] → new_str or nil
str[start, length] = new_str

# 3.根據索引範圍,搜索或賦值0或多個元素
str[range] → new_str or nil
str[range] = aString

# 4.根據正則模式(斜線包圍正則表達式),搜索或賦值匹配到的元素
str[regexp] → new_str or nil
str[regexp] = new_str

# 5.根據正則模式(包含分組匹配),返回給定分組內容
# capture能夠是分組名,也能夠是分組索引號(即反向引用)
# 分組索引號爲0表示regexp匹配的全部內容
# 若是是賦值操做,則替換給定分組的內容
str[regexp, capture] → new_str or nil
str[regexp, integer] = new_str
str[regexp, name] = new_str

# 6.根據給定字符串精確搜索或賦值
str[match_str] → new_str or nil
str[other_str] = new_str

能夠說,Ruby對字符串的索引操做支持的是至關的豐富、完善。下面是一些例子:

a = "hello there"

a[1]                   #=> "e"
a[2, 3]                #=> "llo"
a[2..3]                #=> "ll"

a[-3, 2]               #=> "er"
a[7..-2]               #=> "her"
a[-4..-2]              #=> "her"
a[-2..-4]              #=> ""

a[11, 0]               #=> ""
a[11]                  #=> nil
a[12, 0]               #=> nil
a[12..-1]              #=> nil

a[/[aeiou](.)\1/]      #=> "ell"
a[/[aeiou](.)\1/, 0]   #=> "ell" 等價於上面方式
a[/[aeiou](.)\1/, 1]   #=> "l"   第一個分組內容
a[/[aeiou](.)\1/, 2]   #=> nil   第二個分組

a[/(?<vowel>[aeiou])(?<non_vowel>[^aeiou])/, "non_vowel"] #=> "l"
a[/(?<vowel>[aeiou])(?<non_vowel>[^aeiou])/, "vowel"]     #=> "e"

a["lo"]                #=> "lo"
a["bye"]               #=> nil

s = "hello"
while(s["l"])     # 將全部的l替換成L
    s["l"] = "L"
end

與索引搜索、索引賦值(包括替換、插入、刪除元素)、索引檢查元素是否存在等操做有一些相對應的String方法。以下。

include?()

字符串中是否存在某子串。

include? other_str → true or false
"hello".include? "lo"   #=> true
"hello".include? "ol"   #=> false
"hello".include? ?h     #=> true

index()

搜索某子串或匹配的子串的索引位置。

index(substr[, offset]) → int or nil
index(regexp[, offset]) → int or nil

例如:

"hello".index('e')             #=> 1
"hello".index('lo')            #=> 3
"hello".index('a')             #=> nil
"hello".index(?e)              #=> 1
"hello".index(/[aeiou]/, -3)   #=> 4

replace()

替換字符串爲另外一個字符串,它會替換掉所有內容。它會原處修改字符串

replace(other_str) → str
s = "hello"         #=> "hello"
s.replace "world"   #=> "world"

insert()

在字符串中某個位置處開始插入另外一個字符串。它會原處修改字符串

insert(index, other_str) → str
"abcd".insert(0, 'X')    #=> "Xabcd"
"abcd".insert(3, 'X')    #=> "abcXd"
"abcd".insert(4, 'X')    #=> "abcdX"
"abcd".insert(-3, 'X')   #=> "abXcd"
"abcd".insert(-1, 'X')   #=> "abcdX"

字符串的迭代

由於字符串支持索引操做,因此能夠直接經過索引的方式進行迭代。

a="hello"

i=0
while(i<a.length) do
  puts a[i]
  i += 1
end

0.upto(a.size - 1 ) do |x|
  print a[x]
end

能夠將字符串split成數組,而後經過each迭代。注意,Ruby 1.9裏字符串不能直接經過each迭代了,它再也不max-in Enumerable中的each。

a="hello"

a.split("").each do |x|
  puts x
end

Ruby的字符串類中還定義了4個迭代方式:each_byte、each_char、each_line、each_codepoint。最經常使用的,顯然是each_char。

a = "hello"

a.each_char do |x|
  puts x
end

each_byte、each_codepoint迭代時,獲得的是各字符的ASCII碼或Unicode代碼點。

"我".each_byte.to_a  #=> [230, 136, 145]

"我是單身狗".each_byte.to_a
    #=> [230, 136, 145, 230, 152, 175, 229, 141,
    #   149, 232, 186, 171, 231, 139, 151]

"我".each_codepoint.to_a  #=> [25105]

"我是單身狗".each_codepoint.to_a
    #=> [25105, 26159, 21333, 36523, 29399]

按塊讀取數據(或按段落讀取)時,極可能會用上each_line來迭代緩衝中的一大段數據的每一行。

each_line(separator=$/ [, getline_args]) {|substr| block } → str

每迭代,都將該行傳遞到代碼塊中。

其中:

separator指定記錄(行)分隔符,默認的是\n\r\r\n

getline_args指定讀取到每一行時的所做的操做,目前支持的是:chomp選項,表示將每行尾部的換行符移除掉。這是很是方便的功能,這樣在迭代每一行的時候,不須要手動在代碼塊中使用chomp()了。

str="a line\nb line\nc line\n"
str.each_line {|x| puts "#{x}"}
# 輸出:
=begin
a line
b line
c line
=end

下面是使用chomp參數的功能。

str="a line\nb line\nc line\n"
str.each_line(chomp: true) {|x| puts "#{x}: #{x.length}"}
# 輸出:
=begin
a line: 6
b line: 6
c line: 6
=end

# 等價於
str.each_line {|x| x.chomp!();puts "#{x}: #{x.length}" }
# 輸出:
=begin
a line: 6
b line: 6
c line: 6
=end

下面是指定行分隔符的用法。

str="a line\nb line\nc line\n"
str.each_line("e") {|x| puts "-#{x}-"}
# 輸出:
=begin
-a line-
-
b line-
-
c line-
-
-
=end

# 指定分隔符和chomp參數的時候
str.each_line("e", chomp:true) {|x| puts "-#{x}-"}
-a lin-
-
b lin-
-
c lin-
-
-

字符串的比較

Ruby中典型的幾種方法:<=>、eql?、equal?、==、===。固然,由於實現了<=>,因此也送了< > <= >= between?這幾個比較方法。

其中,對於純字符串對象,==、===、eql?等價,都用於判斷字符串內容是否相同。==是判斷對象的內容是否徹底一致(或者說是相等);===是智能判斷,對於字符串而言,等價於==eql?是根據計算對象hash值進行比較的,對於字符串的hash()方法來講,它是根據字符串長度、內容、編碼三個屬性來生成hash值的。

equal?則最嚴格,只有雙方引用的是同一對象時,才返回true。

說明下eql?比較。下面是eql?()只當不一樣編碼時的比較過程。

>> "我".encode("utf-8").eql?( "我".encode("utf-16") )
=> false

>> "hello".encode("utf-8").eql?( "hello".encode("utf-16") )
=> false

>> "hello".encode("utf-8").eql?( "hello".encode("gbk") )
=> true

此外,String類還實現了casecmpcasecmp?。前者是無視大小寫的<=>,後者是無視大小寫的等值比較。編碼不一樣或一方不是字符串時,返回nil。

casecmp(other_str) → -1, 0, +1, or nil
casecmp?(other_str) → true, false, or nil

例如:

"1234abc".casecmp("1234ABC")  #=> 0

"我".casecmp("我") #=> 0

"\u{c4 d6 dc}" #=> "ÄÖÜ"
"\u{e4 f6 fc}" #=> "äöü"

"\u{c4 d6 dc}".casecmp("\u{e4 f6 fc}")  #=> -1
"\u{c4 d6 dc}".casecmp?("\u{e4 f6 fc}") #=> true

Ruby中字符串內存問題

相關文章
相關標籤/搜索