<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # **第 14 章 字符串類** 正如在 第 4 章中說明的那樣,Ruby 的字符串都是 `String` 類的對象。本章將詳細介紹 `String` 類。 - **字符串的創建** 列舉各種創建字符串的方法。 - **獲取字符串的長度** 介紹獲取字符串長度的方法,說明“字符數”與“字節數”的不同。 - **字符串的索引** 與數組一樣,也是通過索引進行字符串操作,在這一部分中我們會介紹字符串中索引的 用法。 - **字符串的連接與分割** 介紹連接字符串的方法 `+`、`<<`、`concat`,分割字符串的方法 `split`。 - **字符串的比較** 介紹判斷字符串是否相等的方法、以及在進行字符串排序時如何比較字符串的“大小”。 - **換行符的使用方法** 介紹字符串中換行符的使用方法。 - **字符串的檢索與置換** 介紹檢索與置換字符串的方法。 - **字符串與數組的共通方法** 字符串與數組中有不少作用相似的同名方法,在這一部分中我們會集中介紹這些方法。 - **日語字符編碼的轉換** 介紹如何對日語字符串進行必要的字符編碼轉換。 ### **14.1 字符串的創建** 最簡單的字符創建方法就是把字符的集合用 `" "` 或者 `' '` 括起來并直接寫到程序中。 ~~~ str1 = "這也是字符串" str2 = ' 那也是字符串' ~~~ > **注** 在腳本中使用日語時需要注意編碼(encoding)問題,相關內容請參考 19.2 節 1。 1在腳本中使用中文時也同樣需要注意編碼問題。——譯者注 在第 1 章中,我們已經簡單地介紹了用 `" "` 與用 `' '` 創建字符串的不同點。而除此以 外,使用 `" "` 時還可以執行用 `#{}` 括起來的 Ruby 式子,并將執行結果嵌入到字符串中。這個 `#{}` 就稱為內嵌表達式(embedded expressions)。 ~~~ moji = "字符串" str1 = "那也是#{moji}" p str1 #=> "那也是字符串" str2 = ' 那也是#{moji}' p str2 #=> "那也是\#{moji}" ~~~ 使用 `" "` 時,可以顯示使用 `\`轉義的特殊字符(表 14.1)。 **表 14.1 使用 \ 轉義的特殊字符** <table border="1" data-line-num="53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71" width="90%"><thead><tr><th> <p class="表頭單元格">特殊字符</p> </th> <th> <p class="表頭單元格">意義</p> </th> </tr></thead><tbody><tr><td> <p class="表格單元格"><code>\t</code></p> </td> <td> <p class="表格單元格">水平制表符(0x09)</p> </td> </tr><tr><td> <p class="表格單元格"><code>\n</code></p> </td> <td> <p class="表格單元格">換行符(0x0a)</p> </td> </tr><tr><td> <p class="表格單元格"><code>\r</code></p> </td> <td> <p class="表格單元格">回車(0x0d)</p> </td> </tr><tr><td> <p class="表格單元格"><code>\f</code></p> </td> <td> <p class="表格單元格">換頁(0x0c)</p> </td> </tr><tr><td> <p class="表格單元格"><code>\b</code></p> </td> <td> <p class="表格單元格">退格(0x08)</p> </td> </tr><tr><td> <p class="表格單元格"><code>\a</code></p> </td> <td> <p class="表格單元格">響鈴(0x07)</p> </td> </tr><tr><td> <p class="表格單元格"><code>\e</code></p> </td> <td> <p class="表格單元格">溢出(0x1b)</p> </td> </tr><tr><td> <p class="表格單元格"><code>\s</code></p> </td> <td> <p class="表格單元格">空格(0x20)</p> </td> </tr><tr><td> <p class="表格單元格"><code>\v</code></p> </td> <td> <p class="表格單元格">垂直制表符(0x0b)</p> </td> </tr><tr><td> <p class="表格單元格"><code>\<em>nnn</em></code></p> </td> <td> <p class="表格單元格">8 進制表示方式(<em>n</em> 為 0~ 7)</p> </td> </tr><tr><td> <p class="表格單元格"><code>\X<em>nn</em></code></p> </td> <td> <p class="表格單元格">16 進制表示方式(<em>n</em> 為 0 ~ 9、a ~ f、A ~ F)</p> </td> </tr><tr><td> <p class="表格單元格"><code>\C</code><em>x</em>、<code>\C</code>-<em>x</em></p> </td> <td> <p class="表格單元格"><code>Control</code> + <em>x</em></p> </td> </tr><tr><td> <p class="表格單元格"><code>\M</code>-<em>x</em></p> </td> <td> <p class="表格單元格"><code>Meta(Alt)</code> + <em>x</em></p> </td> </tr><tr><td> <p class="表格單元格"><code>\M</code>-\C-<em>x</em></p> </td> <td> <p class="表格單元格"><code>Meta(Alt)</code> + <code>Control</code> + <em>x</em></p> </td> </tr><tr><td> <p class="表格單元格">\<em>x</em></p> </td> <td> <p class="表格單元格">表示 <em>x</em> 字符本身(<em>x</em> 為除以上字符外的字符)</p> </td> </tr><tr><td> <p class="表格單元格">\<em>Unnnn</em></p> </td> <td> <p class="表格單元格">Unicode 字符的 16 進制表示方式(<em>n</em> 為 0 ~ 9、a ~ f、A ~ F)</p> </td> </tr></tbody></table> 下面我們來看看不用 `" "`、`' '` 時應如何創建字符串。 ### **14.1.1 使用 %Q 與 %q** 當創建包含 `"` 或者 `'` 的字符串時,比起使用 `\"`、`\'` 進行轉義,使用 `%Q` 或者 `%q` 會更簡單。 ~~~ desc = %Q{Ruby 的字符串中也可以使用'' 和""。} str = %q|Ruby said, 'Hello world!'| ~~~ 使用 `%Q` 相當于用 `" "` 創建字符串,使用 `%q` 則相當于用 `' '` 創建字符串。 ### **14.1.2 使用 Here Document** Here Document 是源自于 Unix 的 shell 的一種程序寫法,使用 `<<` 來創建字符串。創建包含換行的長字符串時用這個方法是最簡單的。 **<<"結束標識符" 字符串內容 結束標識符** `<<` 后面的結束標識符可以用 `" "` 括著的字符串或者用 `' '` 括著的字符串來定義。用 `" "` 括住的字符串中可以使用轉義字符和內嵌表達式,而用 `' '` 括住的字符串則不會做任何特殊處理,只會原封不動地顯示。另外,使用既沒有 `" "` 也沒有 `' '` 的字符串時,則會被認為是用 `" "` 創建的字符串。 由于 Here Document 整體就是字符串的字面量,因此可以被賦值給變量,也可以作為方法的參數。 我們一般將 `EOF` 或者 `EOB` 作為結束標識符使用。`EOF` 是“End of File”的簡寫,`EOB` 是“End of Block”的簡寫。 Here Document 的結束標識符一定要在行首。因此,在程序縮進比較深的地方使用 Here Document 的話,有時就會像下面的例子那樣,出現整個縮進亂掉的情況。 ~~~ 10.times do |i| 10.times do |j| print(<<"EOB") i: #{i} j: #{j} i*j = #{i*j} EOB end end ~~~ 若希望縮進整齊,可以像下面那樣用 `<<-` 代替 `<<`。這樣程序就會忽略結束標識符前的空格和制表符,結束標識符也就沒有必要一定要寫在行首了。 ~~~ 10.times do |i| 10.times do |j| print(<<-"EOB") i: #{i} j: #{j} i*j = #{i*j} EOB end end ~~~ 這樣操作以后,`print` 和 `EOB` 的縮進就會變得整齊,便于閱讀。下面是將 Here Document 賦值給變量時的做法。 ~~~ str = <<-EOB Hello! Hello! Hello! EOB ~~~ ### **14.1.3 使用 sprintf 方法** 就像用 8 進制或 16 進制的字符串來表示數值那樣,我們也可以用 `sprintf` 方法輸出某種格式的字符串。關于 `sprintf` 的具體使用方法,請參考專欄《printf 方法與 sprintf 方法》。 ### **14.1.4 使用 ``** 通過用 ` 命令 ` 的形式,我們可以得到命令的標準輸出并將其轉換為字符串對象。下面是獲取 Linux 的 ls 命令與 cat 命令的輸出內容的例子: > **執行示例** ~~~ > irb --simple-prompt >> `ls -l /etc/hosts` => "-rw-r--r-- 1 root root 158 Jan 12 2010 /etc/hosts\n" >> puts `cat /etc/hosts` # Host Database # 127.0.0.1 localhost 255.255.255.255 broadcasthost ::1 localhost fe80::1%lo0 localhost => nil ~~~ > **專欄** > **printf 方法與 sprintf 方法** > 雖然 `printf` 方法與 `sprintf` 方法都不是 `String` 類的方法,但在處理字符串時會經常用到它們。下面我們就來看看它們的用法。 > - > **關于 printf 方法** > `printf` 方法可以按照某種格式輸出字符串。例如在輸出數值時,有時我們會需要在數值前補零,或者限定小數點顯示的位數等,在這些情況下,用 `printf` 方法都能非常輕松地實現。 ~~~ 1: n = 123 2: printf("%d\n", n) 3: printf("%4d\n", n) 4: printf("%04d\n", n) 5: printf("%+d\n", n) ~~~ > 執行結果如下。 ~~~ 123 123 0123 +123 ~~~ > `printf` 方法的第 1 個參數表示字符串的輸出格式。而從第 2 個參數開始,往后的參數都會被依次嵌入到格式中 `%` 所對應的位置。 > 在本例中,第 2 行的 `printf` 方法被指定為了 `%d`,這表示輸出的字符是整數。 > `%` 與 `d` 之間還能插入字符。第 3 行的 `printf` 方法里插入了 `4`,這表示按照 4 位整數的格式輸出。我們發現,執行結果中出現了 `123` 這種開頭有 1 個空格的情況,這是因為要把 3 位整數以 4 位的格式輸出,因此就多輸出了 1 個空格。 > 在第 4 行中,`%` 與 `d` 中間插入了 `04`,這表示若輸出的整數位數不足,整數的開頭就會做補零處理。 > 第 5 行中指定了 `+`,這表示輸出的結果一定會包含 `+` 或者 `-`。 > 上面是關于數值格式的指定方法,同樣,我們也可以指定字符串格式。 ~~~ 1: n = "Ruby" 2: printf("Hello,%s!\n", n) 3: printf("Hello,%8s!\n", n) 4: printf("Hello,%-8s!\n", n) ~~~ > 執行結果如下: ~~~ Hello,Ruby! Hello, Ruby! Hello,Ruby ! ~~~ > 本例的第 2 行程序中指定了 `%s`,這表示將參數解析為字符串。參數 `n` 的值為 `Ruby`,因此輸出的字符串為 `Hello,Ruby!`。 > 在第 3 行中,`%` 與 `s` 之間插入了數字 `8`,這表示將 `Ruby` 輸出為 8 位字符串。 > 在第 4 行中,插入的內容為 `-8`,這表示按靠左對齊的方式輸出 8 位字符串。 > - > **關于 sprintf 方法** > `printf` 方法會把內容輸出到控制臺,而 `sprintf` 方法則是把同樣的輸出內容轉換為字符串對象。開頭的 `s` 指的就是 `String`。 ~~~ p sprintf("%d", 123) #=> "123" p sprintf("%04d", 123) #=> "0123" p sprintf("%+d", 123) #=> "+123" p sprintf("Hello,%s!\n", n) #=> "Hello,Ruby!" p sprintf("Hello,%8s!\n", n) #=> "Hello, Ruby!" p sprintf("Hello,%-8s!\n", n) #=> "Hello,Ruby !" ~~~ ### **14.2 獲取字符串的長度** 我們用 `length` 方法和 `size` 方法獲取字符串的長度。兩者都返回相同的結果,大家根據自己的習慣選用即可。 ~~~ p "just another ruby hacker,".length #=> 25 p "just another ruby hacker,".size #=> 25 ~~~ 若是中文字符串,則返回字符數。 ~~~ p ' 面向對象編程語言'.length #=> 8 ~~~ 如果想獲取的不是字符數,而是字節數,可以用 `bytesize` 方法。 ~~~ p ' 面向對象編程語言'.bytesize #=> 24 ~~~ 想知道字符串的長度是否為 0 時,可以使用 `empty?` 方法,該方法常被用于在循環等處理中判斷字符串是否為空。 ~~~ p "".empty? #=> true p "foo".empty? #=> false ~~~ ### **14.3 字符串的索引** 獲取字符串中指定位置的字符,例如獲取“開頭第 3 位的字符”時,與數組一樣,我們也需要用到索引。 ~~~ str = "全新的String 類對象" p str[0] #=> "全" p str[3] #=> "S" p str[9] #=> "類" p str[2, 8] #=> "的String 類" p str[4] #=> "t" ~~~ ### **14.4 字符串的連接** 連接字符串有以下兩種方法(圖 14.1): - **將兩個字符串合并為新的字符串** - **擴展原有的字符串** ![{%}](http://www.ituring.com.cn/figures/2015/Ruby4/21.d14z.001.png) **圖 14.1 連接字符串** 用 `+` 創建新的字符串。 ~~~ hello = "Hello, " world = "World!" str = hello + world p str #=> "Hello, World!" ~~~ 為原有字符串連接其他字符串時,可以使用 `<<` 或者 `concat` 方法。 ~~~ hello = "Hello, " world = "World!" hello << world p hello #=> "Hello, World!" hello.concat(world) p hello #=> "Hello, World!World!" ~~~ 使用 `+` 也能連接原有字符串。 ~~~ hello = hello + world ~~~ 用 `+` 連接原有字符串的結果會被再次賦值給變量 `hello`,這與使用 `<<` 的結果是一樣的。但用 `+` 連接后的字符串對象是新創建的,并沒有改變原有對象,因此即使有其他變量與 `hello` 同時指向原來的對象,那些變量的值也不會改變。而另一方面,由于使用 `<<` 與 `concat` 方法時會改變原有的對象,因此就會對指向同一對象的其他變量產生影響。雖然一般情況下使用 `<<` 與 `concat` 方法會比較有效率,但是我們也應該根據實際情況來選擇適當的字符串連接方法。 ### **14.5 字符串的比較** 我們可以使用 `==` 或者 `!=` 來判斷字符串是否相同。例如在表達式 `str1 == str2` 中,`str1` 與 `str2` 為相同字符串時則返回 `true`,為不同字符串時則返回 `false`。`!=` 與 `==` 表示正相反的意思。 ~~~ p "aaa" == "baa" #=> false p "aaa" == "aa" #=> false p "aaa" == "aaa" #=> true p "aaa" != "baa" #=> true p "aaa" != "aaa" #=> false ~~~ 雖然判斷字符串是否相同時使用 `==` 或者 `!=` 會很方便,但判斷是否為相似的字符串時,使用正則表達式則會簡單得多。 ### **14.5.1 字符串的大小比較** 字符串也有大小關系,但字符串的大小關系并不是由字符串的長度決定的。 ~~~ p ("aaaaa" < "b") #=> true ~~~ 字符串的大小由字符編碼的順序決定。英文字母按照“ABC”的順序排列,日語的平假名與片假名按照“あいうえお”的順序排列 2,在排列英語或日語的字符串時,就可以使用該順序。不過,Ruby 中日語的排序規則與字典中的順序是不同的。例如對“かけ”、“かこ”、“がけ”這 3 個單詞排序時,字典中的順序是“かけ”、“がけ”、“かこ”,而在 Ruby 中,從小到大依次是“かけ”、“かこ”、“がけ”。 2即按日語 50 音的順序排列。——譯者注 另外,由于不能從漢字字符串得到漢字讀音 3,因此,如果想根據讀音排列漢字,就需要事先準備好讀音數據。 3這里特指日語中使用的漢字及其日語讀音,與中文中使用的漢字以及拼音是不同的。——譯者注 中文字符也同樣是由字符編碼的順序決定的。例如,在 UTF-8 字符編碼表中,“一”的編碼為 U+4E00,“丁”的編碼為 U+4E01,兩個字符的比較結果如下。 ~~~ p (" 一" < " 丁") #=> true ~~~ > **專欄** > **字符編碼** > 計算機中的字符都是用數值來管理的,這樣的數值也稱為編碼。 > 字符與數值的對應關系如下表所示。 <table border="1" data-line-num="323 324 325 326 327 328" width="90%"><thead><tr><th> <p class="表頭單元格">字符</p> </th> <th> <p class="表頭單元格">數值</p> </th> </tr></thead><tbody><tr><td> <p class="表格單元格">A</p> </td> <td> <p class="表格單元格">65</p> </td> </tr><tr><td> <p class="表格單元格">B</p> </td> <td> <p class="表格單元格">66</p> </td> </tr><tr><td> <p class="表格單元格">C</p> </td> <td> <p class="表格單元格">67</p> </td> </tr></tbody></table> > 我們把上表那樣字符與數值一一對應的關系稱為字符編碼。但字符編碼并不是一個正確的專業術語,因此我們需要小心使用。 > ASCII 編碼是計算機的基礎。ASCII 編碼是指把英文字母、數值、其他符號、以及換行、制表符這樣的特殊字符集合起來,為它們分配 1 到 127 之間的數值,并使之占用 1 個字節空間(1 個字節可以表示 0 到 255)。另外,在歐美,一種名為 ISO-8859-1 的編碼曾經被廣泛使用,該編碼包含了歐洲常用的基本字符(拼寫符號、原音變音等),并為它們分配 128 到 255之間的數值。也就是說,大部分的字符都是占用 1 個字節的空間。 > 使用日語時不可能不使用平假名、片假名或者漢字,但只用一個字節來表示這些字符是不可能的。因此,為了表示這些字符,用兩個字節表示一個字符的技術就誕生了。 > 不過,非常可惜的是日語的字符編碼并不只有 1 種,而是大概可以分為以下 4 種編碼方式,并且相同編碼方式得到的字符也不一定相等。 <table border="1" data-line-num="337 338 339 340 341 342 343" width="90%"><thead><tr><th> <p class="表頭單元格">編碼方式</p> </th> <th> <p class="表頭單元格">主要使用的地方</p> </th> </tr></thead><tbody><tr><td> <p class="表格單元格">Shift_JIS</p> </td> <td> <p class="表格單元格">Windows 文本</p> </td> </tr><tr><td> <p class="表格單元格">UTF-8</p> </td> <td> <p class="表格單元格">Unix 文本、HTML 等</p> </td> </tr><tr><td> <p class="表格單元格">EUC-JP</p> </td> <td> <p class="表格單元格">Unix 文本</p> </td> </tr><tr><td> <p class="表格單元格">ISO-2022-JP</p> </td> <td> <p class="表格單元格">電子郵件等</p> </td> </tr></tbody></table> > 為字符分配與之對應的數值,這樣的分配方式就稱為字符編碼方式(character encoding scheme)。在日本,常用的編碼方式有 Shift_JIS、EUC-JP、ISO-2022-JP 這 3 種。它們是日語標準字符編碼 JIS X0208 的基礎。字符編碼的名稱一般都直接使用編碼方式的名稱。例如我們會說“這個文本的字符編碼是 EUC,在 Windows 中打開的時候要小心”。 > 編碼方式不同的情況下,即使是相同的字符,對其分配的數值也會不一樣。編碼方式的不同,就是導致俗稱為“亂碼”的問題的原因之一4。 <table border="1" data-line-num="348 349 350 351" width="90%"><thead><tr><th> <p class="表頭單元格">字符</p> </th> <th> <p class="表頭單元格">Shift_JIS</p> </th> <th> <p class="表頭單元格">EUC-JP</p> </th> <th> <p class="表頭單元格">ISO-2022-JP</p> </th> <th> <p class="表頭單元格">UTF-8</p> </th> </tr></thead><tbody><tr><td> <p class="表格單元格">あ</p> </td> <td> <p class="表格單元格">82A0</p> </td> <td> <p class="表格單元格">A4A2</p> </td> <td> <p class="表格單元格">2422</p> </td> <td> <p class="表格單元格">E38182</p> </td> </tr></tbody></table> > 在上表中,あ字符被分配的數值是用 16 進制表示的。據此可以看出,不同的編碼方式所對應的數值是不一樣的。像這樣表示字符的值,我們稱之為碼位(code point)。在 Ruby 中可以用 `String#ord` 方法獲取字符的碼位。 ~~~ #encoding: EUC-JP p "あ".ord #=> 42146(16 進制為A4A2) ~~~ > 另外,雖然 ISO-2022-JP 中使用了與 ASCII 相同的編碼,但實際上也使用了一些小技巧以與 ASCII 有所區別(這些小技巧比較復雜,本專欄就不深入說明了)。 > 最近,一種名為 Unicode 的新的國際化字符編碼慢慢地普及了起來。其中,UTF-8 就是 Unicode 的一種編碼方式。 > 但 Unicode 并不能解決所有編碼問題,它的產生也只是增加了一個不能互相轉換的字符編碼而已。而且,Unicode 中還有多種編碼方式,很有可能導致在意想不到的地方出現問題。現在市面上有很多詳細介紹字符編碼的專業著作,也比較容易找到,有興趣的讀者可以自行查找閱讀。不過,關于字符編碼的理論一來比較深奧,二來存在各種各樣的立場,其中也不乏偏見(筆者愚見)。因此,要想深入了解字符編碼,建議大家不要只看某一本著作,而應該集各家之言,互相比較著閱讀。 4在計算機中用 GB 系列編碼顯示中文字符,最早的 GB 編碼是 GB2312,接著有 GBK,現在最新的是 GB18030,每次擴展都完全保留之前版本的編碼,因此每個新版本都可向下兼容。Windows 平臺的中文字符使用是 GBK 編碼,但在非 Windows 平臺下的中文字符一般都使用 UTF-8 編碼,因此在跨平臺使用時要小心字符編碼問題。——譯者注 ### **14.6 字符串的分割** 用特定字符分割字符串時可以使用 `split` 方法。例如,用冒號(`:`)分割字符串的程序就可以像下面那樣寫: ~~~ column = str.split(/:/) ~~~ 這樣一來,分割后的各項字符串就會以數組的形式賦值給 `column`。 ~~~ str = "高橋:gaoqiao:1234567:000-123-4567" column = str.split(/:/) p column #=> ["高橋", "gaoqiao", "1234567", "000-123-4567"] ~~~ ### **14.7 換行符的使用方法** 用 `each_line` 等方法從標準輸入讀取字符串時,末尾肯定有換行符。然而,在實際處理字符串時,換行符有時候會很礙事。這種情況下,我們就需要刪除多余的換行符(表 14.2)。 **表 14.2 刪除換行符的方法** <table border="1" data-line-num="384 385 386 387 388" width="90%"><thead><tr><th> <p class="表頭單元格">?</p> </th> <th> <p class="表頭單元格">刪除最后一個字符</p> </th> <th> <p class="表頭單元格">刪除換行符</p> </th> </tr></thead><tbody><tr><td> <p class="表格單元格">非破壞性的</p> </td> <td> <p class="表格單元格"><code>chop</code></p> </td> <td> <p class="表格單元格"><code>chomp</code></p> </td> </tr><tr><td> <p class="表格單元格">破壞性的</p> </td> <td> <p class="表格單元格"><code>chop!</code></p> </td> <td> <p class="表格單元格"><code>chomp!</code></p> </td> </tr></tbody></table> `chop` 方法與 `chop!` 方法會刪除字符串行末的任何字符,`chomp` 方法與 `chomp!` 方法則只在行末為換行符時才將其刪除。 ~~~ str = "abcde" # 沒有換行符的情況 newstr = str.chop p newstr #=> "abcd" newstr = str.chomp p newstr #=> "abcde" str2 = "abcd\n" # 有換行符的情況 newstr = str2.chop p newstr #=> "abcd" newstr = str2.chomp p newstr #=> "abcd" ~~~ 用 `each_line` 方法循環讀取新的行時,一般會使用具有破壞性的 `chomp!` 方法直接刪除換行符。 **`f.each_line do |line|` `line.chomp!`  處理`line` `end`** 上面是 `chom p!` 的典型用法。另外,不同的運行環境下,換行符也不同,關于這方面的內容,請參考專欄《關于換行》。 ### **14.8 字符串的檢索與置換** 字符串處理一般都離不開檢索與置換。Ruby 可以很輕松地處理字符串。 ### **14.8.1 字符串的檢索** 我們可以用 `index` 方法或者 `rindex` 方法,來檢查指定的字符串是否存在在某字符串中。 `index` 方法會從左到右檢查字符串中是否存在參數指定的字符串,而 `rindex` 方法則是按照從右到左的順序來檢查(`rindex` 的“r”表示的就是 right(右)的意思)。 ~~~ str = "ABBBBBB" p str.index("BB") #=> 1 p str.rindex("BB") #=> 5 ~~~ 找到字符串時,`index` 方法和 `rindex` 方法會返回字符串首個字符的索引值,沒找到時則返回 `nil`。 另外,如果只是想知道字符串中是否有參數指定的字符串,用 `include?` 方法會更好。 ~~~ str = "ABBBBBB" p str.include?("BB") #=> true ~~~ 除了直接檢索字符串外,Ruby 還可以使用正則表達式來檢索。關于正則表達式,我們將在第 16 章中詳細介紹。 > **專欄** > **關于換行符** > 所謂換行符就是指進行換行的符號。就像在專欄《字符編碼》中介紹的那樣,計算機里使用的字符都被分配了 1 個與之對應的數值,同理,換行符也有 1 個與之對應的數值。不過麻煩的是,不同的 OS 對換行符的處理也不同。 > 下面是常用的 OS 的換行符。這里,LF(LineFeed)的字符為 `\n`,CR(Carriage Return)的字符為 `\r`。 <table border="1" data-line-num="440 441 442 443 444 445" width="90%"><thead><tr><th> <p class="表頭單元格">OS 種類</p> </th> <th> <p class="表頭單元格">換行符</p> </th> </tr></thead><tbody><tr><td> <p class="表格單元格">Unix 系列</p> </td> <td> <p class="表格單元格">LF</p> </td> </tr><tr><td> <p class="表格單元格">Windows 系列</p> </td> <td> <p class="表格單元格">CR + LF</p> </td> </tr><tr><td> <p class="表格單元格">Mac OS 9 以前</p> </td> <td> <p class="表格單元格">CR</p> </td> </tr></tbody></table> > Ruby 中的標準換行符為 LF,一般在 `IO#each_line` 等方法中使用。也就是說,Ruby 在處理 Max OS 9 以前版本的文本時,可能會出現不能正確換行的情況。 > 我們可以通過參數指定 `each_line` 方法所使用的換行符,默認為 `each_line("\n")`。 ### **14.8.2 字符串的置換** 有時我們可能會需要用其他字符串來替換目標字符串中的某一部分。我們把這樣的替換過程稱為置換。用 `sub` 方法與 `gsub` 方法即可實現字符串的置換。 關于 `sub` 方法與 `gsub` 方法,我們將會在 16.6.1 節中詳細介紹。 ### **14.9 字符串與數組的共同方法** 字符串中有很多與數組共同的方法。 當然,繼承了 `Object` 類的實例的方法,在字符串(`String` 類的實例)以及數組(`Array` 類的實例)中也都能使用。除此以外,下面的方法也都能使用。 **(a)與索引操作相關的方法** **(b)與 `Enumerable` 模塊相關的方法** **(c)與連接、反轉(`reverse`)相關的方法** ### **14.9.1 與索引操作相關的方法** 在 14.3 節中我們提到過字符串也能像數組那樣操作索引。數組適用的索引操作方法,也同樣適用于字符串。 - ***s*[*n*] = *str* *s*[*n..m*] = *str* *s*[*n, len*] = *str*** 用 *str* 置換字符串 *s* 的一部分。這里 *n*、*m*、*len* 都是以字符為單位的。 ~~~ str = "abcde" str[2, 1] = "C" p str #=> "abCde" ~~~ - ***s*.`slice!`(*n*) *s*.`slice!`(*n..m*) *s*.`slice!`(*n, len*)** 刪除字符串 *s* 的一部分,并返回刪除的部分。 ~~~ str = "Hello, Ruby." p str.slice!(-1) #=> "." p str.slice!(5..6) #=> ", " p str.slice!(0, 5) #=> "Hello" p str #=> "Ruby" ~~~ ### **14.9.2 返回 Enumerator 對象的方法** 在處理字符串的方法中,有以行為單位進行循環處理的 `each_line` 方法、以字節為單位進行循環處理的 `each_byte` 方法、以及以字符為單位進行循環處理的 `each_char` 方法。調用這些方法時若不帶塊,則會直接返回 `Enumerator` 對象,因此,通過使用這些方法,我們就可以像下面的例子那樣使用 `Enumerable` 模塊的方法了。 ~~~ # 用 collect 方法處理用 each_line 方法獲取的行 str = "壹\n 貳\n 叁\n" tmp = str.each_line.collect do |line| line.chomp 3 end p tmp #=> ["壹壹壹", "貳貳貳", "叁叁叁"] # 用 collect 方法處理用 each_byte 方法獲取的數值 str = "abcde" tmp = str.each_byte.collect do |byte| -byte end p tmp #=> [-97, -98, -99, -100, -101] ~~~ > **專欄** > **Enumerator 類** > 雖然 `Enumerable` 模塊定義了很多方便的方法,但是作為模塊中其他方法的基礎,將遍歷元素的方法限定為 `each` 方法,這一點有些不太靈活。 > `String` 對象有 `each_byte`、`each_line`、`each_char` 等用于循環的方法,如果這些方法都能使用 `each_with_index`、`collect` 等 `Enumerable` 模塊的方法的話,那就方便多了。而 `Enumerator` 類就是為了解決這個問題而誕生的。 > `Enumerator` 類能以 `each` 方法以外的方法為基礎,執行 `Enumerable` 模塊定義的方法。使用 `Enumerator` 類后,我們就可以用 `String#each_line` 方法替代 `each` 方法,從而來執行 `Enumerable` 模塊的方法了。 > 另外,不帶塊的情況下,大部分 Ruby 原生的迭代器在調用時都會返回 `Enumerator` 對象。因此,我們就可以對 `each_line`、`each_byte` 等方法的返回結果繼續使用 `map` 等方法。 ~~~ str = "AA\nBB\nCC\n" p str.each_line.class #=> Enumerator p str.each_line.map{|line| line.chop } #=> ["AA", "BB", "CC"] p str.each_byte.reject{|c| c == 0x0a } #=> [65, 65, 66, 66, 67, 67] ~~~ ### **14.9.3 與連接、反轉(reverse)相關的方法** 除了與 `Enumerable` 模塊、索引等相關的方法外,字符串中還有一些與數組共同的方法。 - ***s*.`concat`(*s2*) *s*+*s2*** 與數組一樣,字符串也能使用 `concat` 方法和 `+` 連接字符串。 ~~~ s = "歡迎" s.concat("光臨") p s #=> "歡迎光臨" ~~~ - ***s*.`delete`(*str*) *s*.`delete!`(*str*)** 從字符串 *s* 中刪除字符串 *str*。 ~~~ s = "防/ 止/ 檢/ 索" p s.delete("/") #=> "防止檢索" ~~~ - ***s*.`reverse` *s*.`reverse!`** 反轉字符串 *s*。 ~~~ s = "晚上好" p s.reverse #=> "好上晚" ~~~ ### **14.10 其他方法** - ***s*.`strip` *s*.`strip!`** 這是刪除字符串 s 開頭和末尾的空白字符的方法。在不需要字符串開頭和末尾的空白時,用這個方法非常方便。 ~~~ p " Thank you. ".strip #=> "Thank you." ~~~ - ***s*.`upcase` *s*.`upcase!` *s*.`downcase` *s*.`downcase!` *s*.`swapcase` *s*.`swapcase!` *s*.`capitalize` *s*.`capitalize!`** 所謂 case 在這里就是指英文字母的大、小寫字母的意思。`~case` 方法就是轉換字母大小寫的方法。 `upcase` 方法會將小寫字母轉換為大寫,大寫字母保持不變。 ~~~ p "Object-Oriented Language".upcase #=> "OBJECT-ORIENTED LANGUAGE" ~~~ `downcase` 方法則剛好相反,將大寫字母轉換小寫。 ~~~ p "Object-Oriented Language".downcase #=> "object-oriented language" ~~~ `swapcase` 方法會將大寫字母轉換為小寫,將小寫字母轉換為大寫。 ~~~ p "Object-Oriented Language".swapcase #=> "oBJECT-oRIENTED lANGUAGE" ~~~ `capitalize` 方法會將首字母轉換為大寫,將其余的字母轉換為小寫。 ~~~ p "Object-Oriented Language".capitalize #=> "Object-oriented language" ~~~ - ***s*.`tr` *s*.`tr!`** 源自于 Unix 的 tr 命令的方法,用于置換字符。 該方法與 `gsub` 方法有點相似,不同點在于 `tr` 方法可以像 `s.tr("a-z", "A-Z")` 這樣一次置換多個字符。 ~~~ p "ABCDE".tr("B", "b") #=> "AbCDE" p "ABCDE".tr("BD", "bd") #=> "AbCdE" p "ABCDE".tr("A-E", "a-e") #=> "abcde" ~~~ 相反,`tr` 方法不能使用正則表達式,也不能指定兩個字符以上的字符串。 ### **14.11 日語字符編碼的轉換** 字符編碼轉換有兩種方法,分別是使用 `encode` 方法和使用 `nkf` 庫的方法。 ### **14.11.1 encode 方法** `encode` 方法是 Ruby 中基本的字符編碼轉換的方法。將字符編碼由 EUC-JP 轉換為 UTF-8,程序可以像下面這樣寫 5 : 5簡體中文的 GBK、GB2312 等編碼也可以用同樣的方法來轉換。——譯者注 ~~~ # encoding: EUC-JP euc_str = "日語EUC 編碼的字符串" utf8_str = euc_str.encode("utf-8") ~~~ 另外,Ruby 中還定義了具有破壞性的 `encode!` 方法。 ~~~ # encodng: EUC-JP str = "日語EUC 編碼的字符串" str.encode!("utf-8") # 將str 轉換為UTF-8 ~~~ `encode` 方法支持的字符編碼,可通過 `Encoding.name_list` 方法獲得。 ### **14.11.2 nkf 庫** 使用 `encode` 方法可以進行字符編碼的轉換,但卻不能進行半角假名與全角假名之間的轉換。全半角假名的轉換我們需要使用 `nkf` 庫。 `nkf` 庫由 `NKF` 模塊提供。`NKF` 模塊是 Unix 的 nkf(Network Kanji code conversion Filter)過濾命令在 Ruby 中的實現。 NKF 模塊用類似于命令行選項的字符串指定字符編碼等。 **`NKF.nkf`( 選項字符串, 轉換的字符串)** nkf 方法的主要參數如表 14.3 所示。 **表 14.3 nkf 的主要參數** <table border="1" data-line-num="630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664" width="90%"><thead><tr><th> <p class="表頭單元格">選項</p> </th> <th> <p class="表頭單元格">意義</p> </th> </tr></thead><tbody><tr><td> <p class="表格單元格"><code>-d</code></p> </td> <td> <p class="表格單元格">從換行符中刪除 CR</p> </td> </tr><tr><td> <p class="表格單元格"><code>-c</code></p> </td> <td> <p class="表格單元格">往換行符中添加 CR</p> </td> </tr><tr><td> <p class="表格單元格"><code>-x</code></p> </td> <td> <p class="表格單元格">不把半角假名轉換為全角假名</p> </td> </tr><tr><td> <p class="表格單元格"><code>-m0</code></p> </td> <td> <p class="表格單元格">抑制 MIME 處理</p> </td> </tr><tr><td> <p class="表格單元格"><code>-h1</code></p> </td> <td> <p class="表格單元格">把片假名轉換為平假名</p> </td> </tr><tr><td> <p class="表格單元格"><code>-h2</code></p> </td> <td> <p class="表格單元格">把平假名轉換為片假名</p> </td> </tr><tr><td> <p class="表格單元格"><code>-h3</code></p> </td> <td> <p class="表格單元格">互換平假名與片假名</p> </td> </tr><tr><td> <p class="表格單元格"><code>-Z0</code></p> </td> <td> <p class="表格單元格">把 JIS X 0208 的數字轉換為 ASCII</p> </td> </tr><tr><td> <p class="表格單元格"><code>-Z1</code></p> </td> <td> <p class="表格單元格">加上 -Z0,把全角空格轉換為半角空格</p> </td> </tr><tr><td> <p class="表格單元格"><code>-Z2</code></p> </td> <td> <p class="表格單元格">加上 -Z0,把全角空格轉換為兩個半角空格</p> </td> </tr><tr><td> <p class="表格單元格"><code>-e</code></p> </td> <td> <p class="表格單元格">輸出的字符編碼為 EUC-JP</p> </td> </tr><tr><td> <p class="表格單元格"><code>-s</code></p> </td> <td> <p class="表格單元格">輸出的字符編碼為 Shift-JIS</p> </td> </tr><tr><td> <p class="表格單元格"><code>-j</code></p> </td> <td> <p class="表格單元格">輸出的字符編碼為 ISO-2022-JP</p> </td> </tr><tr><td> <p class="表格單元格"><code>-w</code></p> </td> <td> <p class="表格單元格">輸出的字符編碼為 UTF-8(無 BOM)</p> </td> </tr><tr><td> <p class="表格單元格"><code>-w8</code></p> </td> <td> <p class="表格單元格">輸出的字符編碼為 UTF-8(有 BOM)</p> </td> </tr><tr><td> <p class="表格單元格"><code>-w80</code></p> </td> <td> <p class="表格單元格">輸出的字符編碼為 UTF-8(無 BOM)</p> </td> </tr><tr><td> <p class="表格單元格"><code>-w16</code></p> </td> <td> <p class="表格單元格">輸出的字符編碼為 UTF-16(Big Endian/ 無 BOM)</p> </td> </tr><tr><td> <p class="表格單元格"><code>-w16B</code></p> </td> <td> <p class="表格單元格">輸出的字符編碼為 UTF-16(Big Endian/ 有 BOM)</p> </td> </tr><tr><td> <p class="表格單元格"><code>-w16B0</code></p> </td> <td> <p class="表格單元格">輸出的字符編碼為 UTF-16(Big Endian/ 無 BOM)</p> </td> </tr><tr><td> <p class="表格單元格"><code>-w16L</code></p> </td> <td> <p class="表格單元格">輸出的字符編碼為 UTF-16(Little Endian/ 有 BOM)</p> </td> </tr><tr><td> <p class="表格單元格"><code>-w16L0</code></p> </td> <td> <p class="表格單元格">輸出的字符編碼為 UTF-16(Little Endian/ 無 BOM)</p> </td> </tr><tr><td> <p class="表格單元格"><code>-E</code></p> </td> <td> <p class="表格單元格">輸入字符編碼為 EUC-JP</p> </td> </tr><tr><td> <p class="表格單元格"><code>-S</code></p> </td> <td> <p class="表格單元格">輸入字符編碼為 Shift-JIS</p> </td> </tr><tr><td> <p class="表格單元格"><code>-J</code></p> </td> <td> <p class="表格單元格">輸入字符編碼為 ISO-2022-JP</p> </td> </tr><tr><td> <p class="表格單元格"><code>-W</code></p> </td> <td> <p class="表格單元格">輸入的字符編碼為 UTF-8(無 BOM)</p> </td> </tr><tr><td> <p class="表格單元格"><code>-W8</code></p> </td> <td> <p class="表格單元格">輸入的字符編碼為 UTF-8(有 BOM)</p> </td> </tr><tr><td> <p class="表格單元格"><code>-W80</code></p> </td> <td> <p class="表格單元格">輸入的字符編碼為 UTF-8(無 BOM)</p> </td> </tr><tr><td> <p class="表格單元格"><code>-W16</code></p> </td> <td> <p class="表格單元格">輸入的字符編碼為 UTF-16(Big Endian/ 無 BOM)</p> </td> </tr><tr><td> <p class="表格單元格"><code>-W16B</code></p> </td> <td> <p class="表格單元格">輸入的字符編碼為 UTF-16(Big Endian/ 有 BOM)</p> </td> </tr><tr><td> <p class="表格單元格"><code>-W16B0</code></p> </td> <td> <p class="表格單元格">輸入的字符編碼為 UTF-16(Big Endian/ 無 BOM)</p> </td> </tr><tr><td> <p class="表格單元格"><code>-W16L</code></p> </td> <td> <p class="表格單元格">輸入的字符編碼為 UTF-16(Little Endian/ 有 BOM)</p> </td> </tr><tr><td> <p class="表格單元格"><code>-W16L0</code></p> </td> <td> <p class="表格單元格">輸入的字符編碼為 UTF-16(Little Endian/ 無 BOM)</p> </td> </tr></tbody></table> 為了避免半角假名轉換為全角假名,或者因電子郵件的特殊字符處理而產生問題,如果只是單純對字符進行編碼轉換的話,一般使用選項 `-x` 和 `-m0`(可以合并書寫 `-xm0`)就足夠了。 下面是把 EUC-JP 字符串轉換為 UTF-8 的例子: ~~~ # encoding: EUC-JP require "nkf" euc_str = "日語EUC 編碼的字符串" utf8_str = NKF.nkf("-E -w -xm0", euc_str) ~~~ 不指定輸入字符編碼時,`nkf` 庫會自動判斷其編碼,基本上都可以按如下方式書寫: ~~~ # encoding: EUC-JP require "nkf" euc_str = "日語EUC 編碼的字符串" utf8_str = NKF.nkf("-w -xm0", euc_str) ~~~ `NKF` 模塊在 Ruby 字符串還未支持 encoding 功能以前就已經開始被使用了。大家可能會感覺選項的指定方法等與現在 Ruby 的風格有點格格不入,這是因為 nkf 庫把其他命令的功能硬搬了過來的緣故。如果不涉及一些太特殊的處理,一般使用 `encode` 就足夠了。 ### **練習題** 1. 有字符串 `"Ruby is an object oriented programming language"`,請創建一個數組,數組元素為這個字符串的各個單詞。 2. 有將 1 的數組按照英文字母順序進行排序。 3. 有不區分大小寫,將 2 的數組按照英文字母順序進行排序。 4. 有把 1 的字符串的全部單詞的首字母轉換為大寫,轉換后的結果為 `"Ruby Is A n Object Oriented Programming Language"`。 5. 有統計 1 的字符串中的字符及其數量,并按下面的形式輸出結果(空格字符 6 個,`'R'`1 個,`'a'`4 個等等)。 ~~~ ' ': ****** 'R': * 'a': **** 'b': ** 'c': * ┊ ~~~ 6. 定義方法 `han2num`, 將漢字數字轉換為 1 ~ 9999 的阿拉伯數字形式,例如將“七千一百二十三”轉換為“`7123`”。 > 參考答案:請到圖靈社區本書的“隨書下載”處下載([http://www.ituring.com.cn/book/1237](http://www.ituring.com.cn/book/1237))。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看