<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>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # **第 19 章 Encoding 類** 在本章中,我們將介紹 `Encoding` 類、以及 Ruby 中編碼的相關用法。 - **Ruby 的編碼與字符串** 介紹 Ruby 中字符串與編碼的使用方法。 - **腳本編碼與魔法注釋** 再次介紹腳本編碼與魔法注釋 - **Encoding 類** 介紹編碼的基礎——`Encoding` 類的相關用法。 - **正則表達式與編碼** 說明正則表達式與編碼的關系。 - **IO 類與編碼** 說明 `IO` 類與編碼的關系。 ### **19.1 Ruby 的編碼與字符串** 字符編碼是計算機進行字符操作的基礎,這一點我們已經在第 14 章的專欄中做過了介紹。就像在專欄中介紹的那樣,字符編碼有多種,而且即使是在同一個程序中,有時候輸入 / 輸出的字符編碼也有可能不一樣。例如程序輸入是 UTF-8 字符編碼,而輸出卻是 Shift_JIS 字符編碼等情況。雖然“あ”的 UTF-8 的字符編碼與 Shift_JIS 的字符編碼實際上是不同的,但經過適當的轉換,也是可以編寫這樣的程序的。 至于程序如何處理字符編碼,不同的編程語言有不同的解決方案。Ruby 的每個字符串對象都包含“字符串數據本身”以及“該數據的字符編碼”兩個信息。其中,關于字符編碼的信息即我們一般所講的編碼。 創建字符串對象一般有兩種方法,一種是在腳本中直接以字面量的形式定義,另外一種是從程序的外部(文件、控制臺、網絡等)獲取字符串數據。數據的獲取方式決定了它的編碼方式。截取字符串的某部分,或者連接多個字符串生成新字符串等的時候,編碼會繼承原有的字符串的編碼。 程序向外部輸出字符串時,必須指定適當的編碼。 Ruby 會按照以下信息決定字符串對象的編碼,或者在輸入 / 輸出處理時轉換編碼。 - **腳本編碼** 決定字面量字符串對象編碼的信息,與腳本的字符編碼一致。詳細內容請參考 19.2 節。 - **內部編碼與外部編碼** 內部編碼是指從外部獲取的數據在程序中如何處理的信息。與之相反,外部編碼是指程序向外部輸出時與編碼相關的信息。兩者都與 `IO` 對象有關聯。詳細內容請參考 19.5 節。 ### **19.2 腳本編碼與魔法注釋** 我們在第 1 章中簡單介紹過魔法注釋。Ruby 腳本的編碼就是通過在腳本的開頭書寫魔法注釋來指定的。 腳本自身的編碼稱為腳本編碼(script encoding)。腳本中的字符串、正則表達式的字面量會依據腳本編碼進行解釋。腳本編碼為 EUC-JP 時,字符串、正則表達式的字面量也都為 EUC-JP。同樣,如果腳本編碼為 Shift_JIS,那么字符串、正則表達式的字面量也為 Shift_JIS。 我們把指定腳本編碼的注釋稱為魔法注釋(magic comment)。Ruby 在解釋腳本前,會先讀取魔法注釋來決定腳本編碼。 魔法注釋必須寫在腳本的首行(第 1 行以 `#! ~` 開頭時,則寫在第 2 行)。下面是將腳本編碼指定為 UTF-8 的例子。 ~~~ # encoding: utf-8 ~~~ > **備注** 在 Unix 中,賦予腳本執行權限后,就可以直接執行腳本。這時,可以在文件開頭以 `#!` 命令的路徑 的形式來指定執行腳本的命令。在本書的例子中,我們經常使用 `>ruby` 腳本名 這樣的形式來表示 在命令行執行腳本的命令為 `ruby`,但若像“`#! /usr/bin/ruby`”這樣,在文件開頭寫上 ruby 命令的路徑的話,那么就能直接以 `>` 腳本名的形式執行腳本了。 此外,為了可以兼容 Emacs、VIM 等編輯器的編碼指定方式,我們也可以像下面這樣寫。 ~~~ # -*- coding: utf-8 -*- # 編輯器為Emacs 的時候 # vim:set fileencoding=utf-8: # 編輯器為VIM 的時候 ~~~ 程序代碼的編碼會嚴格檢查是否與腳本編碼一致。因此,有時候直接寫上日語的字符串后就會產生錯誤 1。 1中文也需要注意同樣的問題。——譯者注 ~~~ # encoding: US-ASCII a = 'こんにちは' #=> invalid multibyte char (US-ASCII) ~~~ 由于 US-ASCII 不能表示日語的字符串,因此會產生錯誤。在 Ruby1.9 中,沒有魔法注釋時默認腳本編碼也為 US-ASCII,因此也會產生這個錯誤。 為了使日語字符能正常顯示,必須指定適當的編碼 2。而在 Ruby2.0 中,由于沒有魔法注釋時的默認腳本編碼為 UTF-8,因此如果代碼是以 UTF-8 編碼編寫的話,那么就無須使用魔法注釋了。 2中文字符也一樣。——譯者注 但有時僅使用魔法注釋是不夠的。例如,使用特殊字符 `\u` 創建字符串后,即使腳本編碼不是 UTF-8,其生成的字符串也一定是 UTF-8。 ~~~ # encoding: EUC-JP a = "\u3042\u3044" puts a #=> "あい" p a.encoding #=> #<Encoding:UTF-8> ~~~ 因此,必須使用 `encode!` 方法明確進行編碼轉換。 ~~~ # encoding: EUC-JP a = "\u3042\u3044" a.encode!("EUC-JP") p a.encoding #=> #<Encoding:EUC-JP> ~~~ 這樣,變量 `a` 的字符串的編碼也就變為 EUC-JP 了。 ### **19.3 Encoding 類** 我們可以用 `String#encoding` 方法來調查字符串的編碼。`String#encoding` 方法返回 `Encoding` 對象。 ~~~ p "こんにちは".encoding #=> #<Encoding:UTF-8> ~~~ 本例中的“こんにちは”字符串對象的編碼為 UTF-8。 > **備注** 日語 Windows 環境中的字符編碼一般為 Windows-31J。這是 Windows 專用的擴展自 Shift_JIS 的編碼,例如,Shift_JIS 中原本并沒有①。Windows-31J 還有一個別名叫 CP932(Microsoft code page932 的意思),在互聯網上就字符編碼討論時,有時候會用到這個名稱。3 3簡體中文 Windows 環境中使用的字符編碼為 GBK(CP936),向下兼容 GB2312 編碼。——譯者注 在腳本中使用不同的編碼時,需要進行必要的轉換。我們可以用 `String#encode` 方法轉換字符串對象的編碼。 ~~~ str = "こんにちは" p str.encoding #=> #<Encoding:UTF-8> str2 = str.encode("EUC-JP") p str2.encoding #=> #<Encoding:EUC-JP> ~~~ 在本例中,我們嘗試把 UTF-8 字符串對象轉換為新的 EUC-JP 字符串對象。 在操作字符串時,Ruby 會自動進行檢查。例如,如果要連接不同編碼的字符串則會產生錯誤。 ~~~ # encoding: utf-8 str1 = "こんにちは" p str1.encoding #=> #<Encoding:UTF-8> str2 = "あいうえお".encode("EUC-JP") p str2.encoding #=> #<Encoding:EUC-JP> str3 = str1 + str2 #=> incompatible character encodings: UTF-8 #=> and EUC-JP(Encoding::CompatibilityError) ~~~ 為了防止錯誤,在連接字符串前,必須使用 `encode` 方法等把兩者轉換為相同的編碼。 還有,在進行字符串比較時,如果編碼不一樣,即使表面的值相同,程序也會將其判斷為不同的字符串。 ~~~ # encoding: utf-8 p "あ" == "あ".encode("Shift_JIS") #=> false ~~~ 另外,在本例中,用 `String#encode` 指定編碼時,除了可以使用編碼名的字符串外,還可以直接使用 `Encoding` 對象來指定。 ### **Encoding 類的方法** 接下來,我們將會介紹 `Encoding` 類的方法。 - **`Encoding.compatible?`(*str1, str2*)** 檢查兩個字符串的兼容性。這里所說的兼容性是指兩個字符串是否可以連接。可兼容則返回字符串連接后的編碼,不可兼容則返回 `nil`。 ~~~ p Encoding.compatible?("AB".encode("EUC-JP"), "あ".encode("UTF-8")) #=> #<Encoding:UTF-8> p Encoding.compatible?("あ".encode("EUC-JP"), "あ".encode("UTF-8")) #=> nil ~~~ AB 這個字符串的編碼無論是 EUC-JP 還是 UTF-8 都是一樣的,因此,將其轉換為 EUC-JP 后也可以與 UTF-8 字符串連接;而あ這個字符串則無法連接,因此返回 `nil`。 - **`Encoding.default_external`** 返回默認的外部編碼,這個值會影響 `IO` 類的外部編碼,詳細內容請參考 19.5 節。 - **`Encoding.default_internal`** 返回默認的內部編碼,這個值會影響 `IO` 類的內部編碼,詳細內容請參考 19.5 節。 - **`Encoding.find`(*name*)** 返回編碼名 *name* 對應的 `Encoding` 對象。預定義的編碼名由不含空格的英文字母、數字與符號構成。查找編碼的時候不區分 *name* 的大小寫。 ~~~ p Encoding.find("Shift_JIS") # => #<Encoding:Shift_JIS> p Encoding.find("shift_JIS") # => #<Encoding:Shift_JIS> ~~~ 表 19.1 為預定義的特殊的編碼名。 **表 19.1 特殊的編碼名** | 名稱 | 意義 | |-----|-----| | `locale` | 根據本地信息決定的編碼 | | `external` | 默認的外部編碼 | | `internal` | 默認的內部編碼 | | `filesystem` | 文件系統的編碼 | - **`Encoding.list` `Encoding.name_list`** 返回 Ruby 支持的編碼一覽表。`list` 方法返回的是 `Encoding` 對象一覽表,Encoding.name_list 返回的是表示編碼名的字符串一覽表,兩者的結果都以數組形式返回。 ~~~ p Encoding.list #=> [#<Encoding:ASCII-8BIT>, #<Encoding:UTF-8>, ... p Encoding.name_list #=> ["ASCII-8BIT", "UTF-8", "US-ASCII", "Big5", ... ~~~ - ***enc*.`name`** 返回 `Encoding` 對象 *enc* 的編碼名。 ~~~ p Encoding.find("shift_jis").name #=> "Shift_JIS" ~~~ - ***enc*.`names`** 像 EUC-JP、eucJP 這樣,有些編碼有多個名稱。這個方法會返回包含 `Encoding` 對象的名稱一覽表的數組。只要是這個方法中的編碼名稱,都可以在通過 `Encoding.find` 方法檢索時使用。 ~~~ enc = Encoding.find("Shift_JIS") p enc.names #=> ["Shift_JIS", "SJIS"] ~~~ > **專欄** > **ASCII-8BIT 與字節串** > ASCII-8BIT 是一個特殊的編碼,被用于表示二進制數據以及字節串。因此有時候我們也稱這個編碼為 BINARY。 > 此外,把字符串對象用字節串形式保存的時候也會用到這個編碼。例如,使用 `Array#pack` 方法將二進制數據生成為字符串時,或者使用 `Marsha1.dump` 方法將對象序列化后的數據生成為字符串時,都會使用該編碼。 > 下面是用 `Array#pack` 方法,把 IP 地址的 4 個數值轉換為 4 個字節的字節串。 ~~~ str = [127, 0, 0, 1].pack("C4") p str #=> "\x7F\x00\x00\x01" p str.encoding # => #<Encoding:ASCII-8BIT> ~~~ > `pack` 方法的參數為字節串化時使用的模式,C4 表示 4 個 8 位的不帶符號的整數。執行結果為 4 個字節的字節串,編碼為 ASCII-8BIT。 > 此外,在使用 `open-uri` 庫等工具通過網絡獲取文件時,有時候并不知道字符編碼是什么。這時候的編碼也默認使用 ASCII-8BIT。 ~~~ # encoding: utf-8 require 'open-uri' str = open("http://www.example.jp/").read p str.encoding #=> #<Encoding:ASCII-8BIT> ~~~ > 即使是編碼為 ASCII-8BIT 的字符串,實際上也還是正常的字符串,只要知道字符編碼,就可以使用 `force_encoding` 方法。這個方法并不會改變字符串的值(二進制數據),而只是改變編碼信息。 ~~~ # encoding: utf-8 require 'open-uri' str = open("http://www.example.jp/").read str.force_encoding("Windows-31J") p str.encoding #=> #<Encoding:Windows-31J> ~~~ > 這樣一來,我們就可以把 ASCII-8BIT 的字符串當作 Windows-31J 字符串來處理了。 > 使用 `force_encoding` 方法時,即使指定了不正確的編碼,也不會馬上產生錯誤,而是在對該字符串進行操作的時候才會產生錯誤。檢查編碼是否正確,可以用 `valid_encoding?` 方法,不正確時則返回 `false`。 ~~~ str = "こんにちは" str.force_encoding("US-ASCII") #=> 不會產生錯誤 str.valid_encoding? #=> false str + "みなさん" #=> Encoding::CompatibilityError ~~~ ### **19.4 正則表達式與編碼** 與字符串同樣,正則表達式也有編碼信息。 正則表達式的編碼即其匹配字符串的編碼。例如,用 EUC-JP 的正則表達式對象去匹配 UTF-8 字符串時就會產生錯誤,反之亦然。 ~~~ # encoding: EUC-JP a = "\u3042\u3044" p /あ/ =~ a #=> incompatible encoding regexp match #=> (EUC-JP regexp with UTF-8 string) #=> (Encoding::CompatibilityError) ~~~ 通常情況下,正則表達式字面量的編碼與代碼的編碼是一樣的。指定其他編碼的時候,可使用 `Regexp` 類的 `new` 方法。在這個方法中,表示模式第 1 個參數的字符串編碼,就是該正則表達式的編碼。 ~~~ str = "模式".encode("EUC-JP") re = Regexp.new(str) p re.encoding # => #<Encoding:EUC-JP> ~~~ ### **19.5 IO 類與編碼** 使用 `IO` 類進行輸入 / 輸出操作時編碼也非常重要。接下來,我們就向大家介紹一下 `IO` 與編碼的相關內容。 ### **19.5.1 外部編碼與內部編碼** 每個 `IO` 對象都包含有外部編碼與內部編碼兩種編碼信息。外部編碼指的是作為輸入 / 輸出對象的文件、控制臺等的編碼,內部編碼指的是 Ruby 腳本中的編碼。`IO` 對象的編碼的相關方法如表 19.2 所示。 **表 19.2 與 IO 類編碼相關的方法** <table border="1" data-line-num="256 257 258 259 260 261" width="90%"><thead><tr><th> <p class="表頭單元格">方法名</p> </th> <th> <p class="表頭單元格">意義</p> </th> </tr></thead><tbody><tr><td> <p class="表格單元格"><code>IO#external_encoding</code></p> </td> <td> <p class="表格單元格">返回 <code>IO</code> 的外部編碼</p> </td> </tr><tr><td> <p class="表格單元格"><code>IO#internal_encoding</code></p> </td> <td> <p class="表格單元格">返回 <code>IO</code> 的內部編碼</p> </td> </tr><tr><td> <p class="表格單元格"><code>IO#set_encoding</code></p> </td> <td> <p class="表格單元格">設定 <code>IO</code> 的編碼</p> </td> </tr></tbody></table> 沒有明確指定編碼時,`IO` 對象的外部編碼與內部編碼各自使用其默認值 `Encoding.default_external`、`Encoding.default_internal`。默認情況下,外部編碼會基于各個系統的本地信息設定,內部編碼不設定。Windows 環境下的編碼信息如下所示。 ~~~ p Encoding.default_external #=> #<Encoding:Windows-31J> p Encoding.default_internal #=> nil File.open("foo.txt") do |f| p f.external_encoding #=> #<Encoding:Windows-31J> p f.internal_encoding #=> nil end ~~~ ### **19.5.2 編碼的設定** 在剛才的例子中我們打開了文本文件(foo.txt),但 `IO` 對象(`File` 對象)的編碼與文件的實際內容其實是沒關系的。因為編碼原本就只是用來說明如何處理字符的信息,因此對文本文件以外的文件并沒有多大作用。 在 17.3 節中說明如何按字節操作文件時,我們介紹了 `IO#seek` 方法與 `IO#read`(*size*)方法,這些方法都不受編碼影響,對任何數據都可以進行讀寫操作。`IO#read`(*size*)方法讀取的字符串的編碼為表示二進制數據的 ASCII-8BIT。 設定 `IO` 對象的編碼信息,可以通過使用 `IO#set_encoding` 方法,或者在 `File.open` 方法的參數中指定編碼來進行。 - ***io*.`set_encoding`(*encoding*)** `IO#set_encoding` 方法以 " 外部編碼名 : 內部編碼名 " 的形式指定字符串 *encoding*。把外部編碼設置為 Shift_JIS,內部編碼設置為 UTF-8 的時候,可以像下面那樣設定。 ~~~ $stdin.set_encoding("Shift_JIS:UTF-8") p $stdin.external_encoding #=> #<Encoding:Shift_JIS> p $stdin.internal_encoding #=> #<Encoding:UTF-8> ~~~ - **`File.open`(*file,* "*mode:encoding*")** 為了在打開文件 *file* 時通過 `File.open` 方法指定編碼 *encoding*,可以在第二個參數中指定 *mode* 的后面用冒號(`:`)分割,并按順序指定外部編碼以及內部編碼(內部編碼可省略)。 ~~~ # 指定外部編碼為UTF-8 File.open("foo.txt", "w:UTF-8")   # 指定外部編碼為Shift_JIS # 指定內部編碼為UTF-8 File.open("foo.txt", "r:Shift_JIS:UTF-8") ~~~ ### **19.5.3 編碼的作用** 接下來,我們來看看 `IO` 對象中設定的編碼信息是如何工作的。 - **輸出時編碼的作用** 外部編碼影響 `IO` 的寫入(輸出)。在輸出的時候,會基于每個字符串的原有編碼和 `IO` 對象的外部編碼進行編碼的轉換(因此輸出用的 `IO` 對象不需要指定內部編碼)。 如果沒有設置外部編碼,或者字符串的編碼與外部編碼一致,則不會進行編碼的轉換。在需要進行轉換的時候,如果輸出的字符串的編碼不正確(比如實際上是日語字符串,但編碼卻是中文),或者是無法互相轉換的編碼組合(例如用于日語與中文的編碼),這時程序就會拋出異常。 ![{%}](https://box.kancloud.cn/2015-10-26_562e0206f36dc.png) **圖 19.1 輸出時與編碼相關的行為** - **輸入時編碼的作用** `IO` 的讀取(輸入)會稍微復雜一點。首先,如果外部編碼沒有設置,則會使用 `Encoding.default_external` 的值作為外部編碼。 設定了外部編碼,但內部編碼沒設定的時候,則會將讀取的字符串的編碼設置為 `IO` 對象的外部編碼。這種情況下并不會進行編碼的轉換,而是將文件、控制臺輸入的數據原封不動地保存為 `String` 對象。 最后,外部編碼和內部編碼都設定的時候,則會執行由外部編碼轉換為內部編碼的處理。輸入與輸出的情況一樣,在編碼轉換的過程中如果數據格式或者編碼組合不正確,程序都會拋出異常。 大家或許會感覺有點復雜,其實只要使用的環境與實際使用的數據的編碼一致,我們就不需要考慮編碼的轉換。另外一方面,如果執行環境與數據的編碼不一致,那么我們就需要在程序里有意識地處理編碼問題。 ![{%}](https://box.kancloud.cn/2015-10-26_562e020718d80.png) **圖 19.2 輸入時與編碼相關的行為** > **專欄** > **UTF8-MAC 編碼** > 在 Mac OS X 中,文件名中如果使用了濁點或者半濁點字符4,有時候就會產生一些奇怪的現象。 > 例如,創建文件 `ルビー.txt` 并執行下面的程序,可以發現,預計執行結果應該為 `found.`,但實際結果卻是 `not found.`。 > **代碼清單 utf8mac.rb** ~~~ # encoding: utf-8 Dir.glob("*.txt") do |filename| if filename == "ルビー.txt" puts "found."; exit end end puts "not found." ~~~ > > **執行示例** ~~~ > touch ルビー.txt > ruby utf8mac.rb not found. ~~~ > 另一方面,執行以下腳本,這次會輸出 `found.`。 > **代碼清單 utf8mac_fix.rb** ~~~ # encoding: utf-8 Dir.glob("*.txt") do |filename| if filename.encode("UTF8-MAC") == "ルビー.txt".encode("UTF8-MAC") puts "found."; exit end end puts "not found." ~~~ > > **執行示例** ~~~ > touch ルビー.txt > ruby utf8mac_fix.rb found. ~~~ > 這是由于 Mac OS X 中的文件系統使用的編碼不是 UTF-8,而是一種名為 UTF8-MAC(或者叫 UTF-8-MAC)的編碼的緣故。 > 那么,UTF8-MAC 是什么樣的編碼呢。我們通過下面的例子來看一下。 > **代碼清單 utf8mac_str.rb** ~~~ # encoding: utf-8 str = "ビ" puts "size: #{str.size}" p str.each_byte.map{|b| b.to_s(16)} puts "size: #{str.encode("UTF8-MAC").size}" p str.encode("UTF8-MAC").each_byte.map{|b| b.to_s(16)} ~~~ > > **執行示例** ~~~ > ruby utf8mac_str.rb size: 1 ["e3", "83", "93"] size: 2 ["e3", "83", "92", "e3", "82", "99"] ~~~ > 本例表示的是在 UTF-8 和 UTF8-MAC 這兩種編碼方式的情況下,分別以 16 進制的形式輸出字符串 " ビ " 的長度以及各個字節的值。從結果中我們可以看出,UTF-8 時的值為“`ec,83,93`”,UTF8-MAC 時則是“`e3,83,92,e3,82,99`”。而轉換為 UTF8-MAC 后,字符串的長度也變為了兩個字符。 > 在 UTF8-MAC 中,字符ビ(Unicode 中為 U+30D3)會分解為字符匕(U+30D2)與濁點字符(U+3099)兩個字符。用 UTF-8 表示則為 `8392E3` 與 `8299E3` 兩個字節串,因此就得到了之前的結果。 > 像這樣,如果把 Mac OS X 的文件系統當作是普通的 UTF-8 看待,往往就會有意料之外的事情發生。在操作日語文件、目錄時務必注意這個問題 5。 4即日語字母右上角的兩個小點和小圓圈。——譯者注 5除了日語字母外,一些“含附加符號”的字母也會做同樣的處理。例如,字符“ü”會拆分為字符“u”與字符“¨”的組合。雖然中文字符中一般很少有“附加符號”的情況,但在處理中文字符以外的字符時需要小心這個“陷阱”。——譯者注 ### **練習題** 1. 定義 `to_utf8(str_gbk, str_gb2312)` 方法,連接 GBK 字符串 `str_gbk` 以及 GB2312 字符串 `str_gb2312`,并將連接后的字符串的編碼轉換為 UTF-8 后返回。 2. 創建編碼為 GBK 的文本文件,文件內容為“你好”,定義一個腳本,讀取該文件并將其按 UTF-8 編碼方式輸出。 3. 請找出 UTF-8 字符串 `str`,要求其 `str.encode("GB18030")` 與 `str.encode("GBK")` 的結果不一樣。 4. 在剛才的專欄的第二個腳本中,比較時雙方都轉換為了 UTF8-MAC。請修改 `if` 語句的條件,使 `ルビー.txt` 在比較時可以保持 UTF-8 編碼的形式。 > 參考答案:請到圖靈社區本書的“隨書下載”處下載([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>

                              哎呀哎呀视频在线观看