<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-26  評(píng)論-111  文章-19  trackbacks-0

    UTF-8 and Unicode FAQ

    by Markus Kuhn

    中國LINUX論壇翻譯小組 xLoneStar[譯] 2000年2月

    這篇文章說明了在 POSIX 系統(tǒng) (Linux,Unix) 上使用 Unicode/UTF-8 所需要的信息. 在將來不遠(yuǎn)的幾年里, Unicode 已經(jīng)很接近于取代 ASCII 與 Latin-1 編碼的位置了. 它不僅允許你處理處理事實(shí)上存在于地球上的任何語言文字, 而且提供了一個(gè)全面的數(shù)學(xué)與技術(shù)符號(hào)集, 因此可以簡(jiǎn)化科學(xué)信息交換.

    UTF-8 編碼提供了一種簡(jiǎn)便而向后兼容的方法, 使得那種完全圍繞 ASCII 設(shè)計(jì)的操作系統(tǒng), 比如 Unix, 也可以使用 Unicode. UTF-8 就是 Unix, Linux 已經(jīng)類似的系統(tǒng)使用 Unicode 的方式. 現(xiàn)在是你了解它的時(shí)候了.

    什么是 UCS 和 ISO 10646?

    國際標(biāo)準(zhǔn) ISO 10646 定義了 通用字符集 (Universal Character Set, UCS). UCS 是所有其他字符集標(biāo)準(zhǔn)的一個(gè)超集. 它保證與其他字符集是雙向兼容的. 就是說, 如果你將任何文本字符串翻譯到 UCS格式, 然后再翻譯回原編碼, 你不會(huì)丟失任何信息.

    UCS 包含了用于表達(dá)所有已知語言的字符. 不僅包括拉丁語,希臘語, 斯拉夫語,希伯來語,阿拉伯語,亞美尼亞語和喬治亞語的描述, 還包括中文, 日文和韓文這樣的象形文字, 以及 平假名, 片假名, 孟加拉語, 旁遮普語果魯穆奇字符(Gurmukhi), 泰米爾語, 印.埃納德語(Kannada), Malayalam, 泰國語, 老撾語, 漢語拼音(Bopomofo), Hangul, Devangari, Gujarati, Oriya, Telugu 以及其他數(shù)也數(shù)不清的語. 對(duì)于還沒有加入的語言, 由于正在研究怎樣在計(jì)算機(jī)中最好地編碼它們, 因而最終它們都將被加入. 這些語言包括 Tibetian, 高棉語, Runic(古代北歐文字), 埃塞俄比亞語, 其他象形文字, 以及各種各樣的印-歐語系的語言, 還包括挑選出來的藝術(shù)語言比如 Tengwar, Cirth 和 克林貢語(Klingon). UCS 還包括大量的圖形的, 印刷用的, 數(shù)學(xué)用的和科學(xué)用的符號(hào), 包括所有由 TeX, Postscript, MS-DOS,MS-Windows, Macintosh, OCR 字體, 以及許多其他字處理和出版系統(tǒng)提供的字符.

    ISO 10646 定義了一個(gè) 31 位的字符集. 然而, 在這巨大的編碼空間中, 迄今為止只分配了前 65534 個(gè)碼位 (0x0000 到 0xFFFD). 這個(gè) UCS 的 16位子集稱為 基本多語言面 (Basic Multilingual Plane, BMP). 將被編碼在 16 位 BMP 以外的字符都屬于非常特殊的字符(比如象形文字), 且只有專家在歷史和科學(xué)領(lǐng)域里才會(huì)用到它們. 按當(dāng)前的計(jì)劃, 將來也許再也不會(huì)有字符被分配到從 0x000000 到 0x10FFFF 這個(gè)覆蓋了超過 100 萬個(gè)潛在的未來字符的 21 位的編碼空間以外去了. ISO 10646-1 標(biāo)準(zhǔn)第一次發(fā)表于 1993 年, 定義了字符集與 BMP 中內(nèi)容的架構(gòu). 定義 BMP 以外的字符編碼的第二部分 ISO 10646-2 正在準(zhǔn)備中, 但也許要過好幾年才能完成. 新的字符仍源源不斷地加入到 BMP 中, 但已經(jīng)存在的字符是穩(wěn)定的且不會(huì)再改變了.

    UCS 不僅給每個(gè)字符分配一個(gè)代碼, 而且賦予了一個(gè)正式的名字. 表示一個(gè) UCS 或 Unicode 值的十六進(jìn)制數(shù), 通常在前面加上 "U+", 就象 U+0041 代表字符"拉丁大寫字母A". UCS 字符 U+0000 到 U+007F 與 US-ASCII(ISO 646) 是一致的, U+0000 到 U+00FF 與 ISO 8859-1(Latin-1) 也是一致的. 從 U+E000 到 U+F8FF, 已經(jīng) BMP 以外的大范圍的編碼是為私用保留的.

    什么是組合字符?

    UCS里有些編碼點(diǎn)分配給了 組合字符.它們類似于打字機(jī)上的無間隔重音鍵. 單個(gè)的組合字符不是一個(gè)完整的字符. 它是一個(gè)類似于重音符或其他指示標(biāo)記, 加在前一個(gè)字符后面. 因而, 重音符可以加在任何字符后面. 那些最重要的被加重的字符, 就象普通語言的正字法(orthographies of common languages)里用到的那種, 在 UCS 里都有自己的位置, 以確保同老的字符集的向后兼容性. 既有自己的編碼位置, 又可以表示為一個(gè)普通字符跟隨一個(gè)組合字符的被加重字符, 被稱為 預(yù)作字符(precomposed characters). UCS 里的預(yù)作字符是為了同沒有預(yù)作字符的舊編碼, 比如 ISO 8859, 保持向后兼容性而設(shè)的. 組合字符機(jī)制允許在任何字符后加上重音符或其他指示標(biāo)記, 這在科學(xué)符號(hào)中特別有用, 比如數(shù)學(xué)方程式和國際音標(biāo)字母, 可能會(huì)需要在一個(gè)基本字符后組合上一個(gè)或多個(gè)指示標(biāo)記.

    組合字符跟隨著被修飾的字符. 比如, 德語中的元音變音字符 ("拉丁大寫字母A 加上分音符"), 既可以表示為 UCS 碼 U+00C4 的預(yù)作字符, 也可以表示成一個(gè)普通 "拉丁大寫字母A" 跟著一個(gè)"組合分音符":U+0041 U+0308 這樣的組合. 當(dāng)需要堆疊多個(gè)重音符, 或在一個(gè)基本字符的上面和下面都要加上組合標(biāo)記時(shí), 可以使用多個(gè)組合字符. 比如在泰國文中, 一個(gè)基本字符最多可加上兩個(gè)組合字符.

    什么是 UCS 實(shí)現(xiàn)級(jí)別?

    不是所有的系統(tǒng)都需要支持象組合字符這樣的 UCS 里所有的先進(jìn)機(jī)制. 因此 ISO 10646 指定了下列三種實(shí)現(xiàn)級(jí)別:

    級(jí)別1
    不支持組合字符和 Hangul Jamo 字符 (一種特別的, 更加復(fù)雜的韓國文的編碼, 使用兩個(gè)或三個(gè)子字符來編碼一個(gè)韓文音節(jié))
    級(jí)別2
    類似于級(jí)別1, 但在某些文字中, 允許一列固定的組合字符 (例如, 希伯來文, 阿拉伯文, Devangari, 孟加拉語, 果魯穆奇語, Gujarati, Oriya, 泰米爾語, Telugo, 印.埃納德語, Malayalam, 泰國語和老撾語). 如果沒有這最起碼的幾個(gè)組合字符, UCS 就不能完整地表達(dá)這些語言.
    級(jí)別3
    支持所有的 UCS 字符, 例如數(shù)學(xué)家可以在任意一個(gè)字符上加上一個(gè) tilde(顎化符號(hào),西班牙語字母上面的~)或一個(gè)箭頭(或兩者都加).

    什么是 Unicode?

    歷史上, 有兩個(gè)獨(dú)立的, 創(chuàng)立單一字符集的嘗試. 一個(gè)是國際標(biāo)準(zhǔn)化組織(ISO)的 ISO 10646 項(xiàng)目, 另一個(gè)是由(一開始大多是美國的)多語言軟件制造商組成的協(xié)會(huì)組織的 Unicode 項(xiàng)目. 幸運(yùn)的是, 1991年前后, 兩個(gè)項(xiàng)目的參與者都認(rèn)識(shí)到, 世界不需要兩個(gè)不同的單一字符集. 它們合并雙方的工作成果, 并為創(chuàng)立一個(gè)單一編碼表而協(xié)同工作. 兩個(gè)項(xiàng)目仍都存在并獨(dú)立地公布各自的標(biāo)準(zhǔn), 但 Unicode 協(xié)會(huì)和 ISO/IEC JTC1/SC2 都同意保持 Unicode 和 ISO 10646 標(biāo)準(zhǔn)的碼表兼容, 并緊密地共同調(diào)整任何未來的擴(kuò)展.

    那么 Unicode 和 ISO 10646 不同在什么地方?

    Unicode 協(xié)會(huì)公布的 Unicode 標(biāo)準(zhǔn) 嚴(yán)密地包含了 ISO 10646-1 實(shí)現(xiàn)級(jí)別3的基本多語言面. 在兩個(gè)標(biāo)準(zhǔn)里所有的字符都在相同的位置并且有相同的名字.

    Unicode 標(biāo)準(zhǔn)額外定義了許多與字符有關(guān)的語義符號(hào)學(xué), 一般而言是對(duì)于實(shí)現(xiàn)高質(zhì)量的印刷出版系統(tǒng)的更好的參考. Unicode 詳細(xì)說明了繪制某些語言(比如阿拉伯語)表達(dá)形式的算法, 處理雙向文字(比如拉丁與希伯來文混合文字)的算法和 排序與字符串比較 所需的算法, 以及其他許多東西.

    另一方面, ISO 10646 標(biāo)準(zhǔn), 就象廣為人知的 ISO 8859 標(biāo)準(zhǔn)一樣, 只不過是一個(gè)簡(jiǎn)單的字符集表. 它指定了一些與標(biāo)準(zhǔn)有關(guān)的術(shù)語, 定義了一些編碼的別名, 并包括了規(guī)范說明, 指定了怎樣使用 UCS 連接其他 ISO 標(biāo)準(zhǔn)的實(shí)現(xiàn), 比如 ISO 6429 和 ISO 2022. 還有一些與 ISO 緊密相關(guān)的, 比如 ISO 14651 是關(guān)于 UCS 字符串排序的.

    考慮到 Unicode 標(biāo)準(zhǔn)有一個(gè)易記的名字, 且在任何好的書店里的 Addison-Wesley 里有, 只花費(fèi) ISO 版本的一小部分, 且包括更多的輔助信息, 因而它成為使用廣泛得多的參考也就不足為奇了. 然而, 一般認(rèn)為, 用于打印 ISO 10646-1 標(biāo)準(zhǔn)的字體在某些方面的質(zhì)量要高于用于打印 Unicode 2.0的. 專業(yè)字體設(shè)計(jì)者總是被建議說要兩個(gè)標(biāo)準(zhǔn)都實(shí)現(xiàn), 但一些提供的樣例字形有顯著的區(qū)別. ISO 10646-1 標(biāo)準(zhǔn)同樣使用四種不同的風(fēng)格變體來顯示表意文字如中文, 日文和韓文 (CJK), 而 Unicode 2.0 的表里只有中文的變體. 這導(dǎo)致了普遍的認(rèn)為 Unicode 對(duì)日本用戶來說是不可接收的傳說, 盡管是錯(cuò)誤的.

    什么是 UTF-8?

    首先 UCS 和 Unicode 只是分配整數(shù)給字符的編碼表. 現(xiàn)在存在好幾種將一串字符表示為一串字節(jié)的方法. 最顯而易見的兩種方法是將 Unicode 文本存儲(chǔ)為 2 個(gè) 或 4 個(gè)字節(jié)序列的串. 這兩種方法的正式名稱分別為 UCS-2 和 UCS-4. 除非另外指定, 否則大多數(shù)的字節(jié)都是這樣的(Bigendian convention). 將一個(gè) ASCII 或 Latin-1 的文件轉(zhuǎn)換成 UCS-2 只需簡(jiǎn)單地在每個(gè) ASCII 字節(jié)前插入 0x00. 如果要轉(zhuǎn)換成 UCS-4, 則必須在每個(gè) ASCII 字節(jié)前插入三個(gè) 0x00.

    在 Unix 下使用 UCS-2 (或 UCS-4) 會(huì)導(dǎo)致非常嚴(yán)重的問題. 用這些編碼的字符串會(huì)包含一些特殊的字符, 比如 '\0' 或 '/', 它們?cè)?文件名和其他 C 庫函數(shù)參數(shù)里都有特別的含義. 另外, 大多數(shù)使用 ASCII 文件的 UNIX 下的工具, 如果不進(jìn)行重大修改是無法讀取 16 位的字符的. 基于這些原因, 在文件名, 文本文件, 環(huán)境變量等地方, UCS-2 不適合作為 Unicode 的外部編碼.

    在 ISO 10646-1 Annex RRFC 2279 里定義的 UTF-8 編碼沒有這些問題. 它是在 Unix 風(fēng)格的操作系統(tǒng)下使用 Unicode 的明顯的方法.

    UTF-8 有一下特性:

    • UCS 字符 U+0000 到 U+007F (ASCII) 被編碼為字節(jié) 0x00 到 0x7F (ASCII 兼容). 這意味著只包含 7 位 ASCII 字符的文件在 ASCII 和 UTF-8 兩種編碼方式下是一樣的.
    • 所有 >U+007F 的 UCS 字符被編碼為一個(gè)多個(gè)字節(jié)的串, 每個(gè)字節(jié)都有標(biāo)記位集. 因此, ASCII 字節(jié) (0x00-0x7F) 不可能作為任何其他字符的一部分.
    • 表示非 ASCII 字符的多字節(jié)串的第一個(gè)字節(jié)總是在 0xC0 到 0xFD 的范圍里, 并指出這個(gè)字符包含多少個(gè)字節(jié). 多字節(jié)串的其余字節(jié)都在 0x80 到 0xBF 范圍里. 這使得重新同步非常容易, 并使編碼無國界, 且很少受丟失字節(jié)的影響.
    • 可以編入所有可能的 231個(gè) UCS 代碼
    • UTF-8 編碼字符理論上可以最多到 6 個(gè)字節(jié)長(zhǎng), 然而 16 位 BMP 字符最多只用到 3 字節(jié)長(zhǎng).
    • Bigendian UCS-4 字節(jié)串的排列順序是預(yù)定的.
    • 字節(jié) 0xFE 和 0xFF 在 UTF-8 編碼中從未用到.

    下列字節(jié)串用來表示一個(gè)字符. 用到哪個(gè)串取決于該字符在 Unicode 中的序號(hào).

    U-00000000 - U-0000007F: 0xxxxxxx
    U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
    U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
    U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

    xxx 的位置由字符編碼數(shù)的二進(jìn)制表示的位填入. 越靠右的 x 具有越少的特殊意義. 只用最短的那個(gè)足夠表達(dá)一個(gè)字符編碼數(shù)的多字節(jié)串. 注意在多字節(jié)串中, 第一個(gè)字節(jié)的開頭"1"的數(shù)目就是整個(gè)串中字節(jié)的數(shù)目.

    例如: Unicode 字符 U+00A9 = 1010 1001 (版權(quán)符號(hào)) 在 UTF-8 里的編碼為:

    11000010 10101001 = 0xC2 0xA9

    而字符 U+2260 = 0010 0010 0110 0000 (不等于) 編碼為:

    11100010 10001001 10100000 = 0xE2 0x89 0xA0

    這種編碼的官方名字拼寫為 UTF-8, 其中 UTF 代表 UCS Transformation Format. 請(qǐng)勿在任何文檔中用其他名字 (比如 utf8 或 UTF_8) 來表示 UTF-8, 當(dāng)然除非你指的是一個(gè)變量名而不是這種編碼本身.

    什么編程語言支持 Unicode?

    在大約 1993 年之后開發(fā)的大多數(shù)現(xiàn)代編程語言都有一個(gè)特別的數(shù)據(jù)類型, 叫做 Unicode/ISO 10646-1 字符. 在 Ada95 中叫 Wide_Character, 在 Java 中叫 char.

    ISO C 也詳細(xì)說明了處理多字節(jié)編碼和寬字符 (wide characters) 的機(jī)制, 1994 年 9 月 Amendment 1 to ISO C 發(fā)表時(shí)又加入了更多. 這些機(jī)制主要是為各類東亞編碼而設(shè)計(jì)的, 它們比處理 UCS 所需的要健壯得多. UTF-8 是 ISO C 標(biāo)準(zhǔn)調(diào)用多字節(jié)字符串的編碼的一個(gè)例子, wchar_t 類型可以用來存放 Unicode 字符.

    在 Linux 下該如何使用 Unicode?

    在 UTF-8 之前, 不同地區(qū)的 Linux 用戶使用各種各樣的 ASCII 擴(kuò)展. 最普遍的歐洲編碼是 ISO 8859-1 和 ISO 8859-2, 希臘編碼 ISO 8859-7, 俄國編碼 KOI-8, 日本編碼 EUC 和 Shift-JIS, 等等. 這使得 文件的交換非常困難, 且應(yīng)用軟件必須特別關(guān)心這些編碼的不同之處.

    最終, Unicode 將取代所有這些編碼, 主要通過 UTF-8 的形式. UTF-8 將應(yīng)用在

    • 文本文件 (源代碼, HTML 文件, email 消息, 等等)
    • 文件名
    • 標(biāo)準(zhǔn)輸入與標(biāo)準(zhǔn)輸出, 管道
    • 環(huán)境變量
    • 剪切與粘貼選擇緩沖區(qū)
    • telnet, modem 和到終端模擬器的串口連接
    • 以及其他地方以前用ASCII來表示的字節(jié)串

    在 UTF-8 模式下, 終端模擬器, 比如 xterm 或 Linux console driver, 將每次按鍵轉(zhuǎn)換成相應(yīng)的 UTF-8 串, 然后發(fā)送到前臺(tái)進(jìn)程的 stdin 里. 類似的, 任何進(jìn)程在 stdout 上的輸出都將發(fā)送到終端模擬器, 在那里用一個(gè) UTF-8 解碼器進(jìn)行處理, 之后再用一種 16 位的字體顯示出來.

    只有在功能完善的多語言字處理器包里才可能有完全的 Unicode 功能支持. 而廣泛用在 Linux 里用于取代 ASCII 和其他 8 位字符集的方案則要簡(jiǎn)單得多. 第一步, Linux 終端模擬器和命令行工具將只是轉(zhuǎn)變到 UTF-8. 這意味著只用到 級(jí)別1 的 ISO 10646-1 實(shí)現(xiàn) (沒有組合字符), 且只支持那些不需要更多處理的語言象 拉丁, 希臘, 斯拉夫 和許多科學(xué)用符號(hào). 在這個(gè)級(jí)別上, UCS 支持與 ISO 8859 支持類似, 唯一顯著的區(qū)別是現(xiàn)在我們有幾千種字符可以用了, 其中的字符可以用多字節(jié)串來表示.

    總有一天 Linux 會(huì)當(dāng)然地支持組合字符, 但即便如此, 對(duì)于組合字符串, 預(yù)作字符(如何可用的話)仍將是首選的. 更正式地, 在 Linux 下用 Unicode 對(duì)文本編碼的首選的方法應(yīng)該是定義在 Unicode Technical Report #15 里的 Normalization Form C.

    在今后的一個(gè)階段, 人們可以考慮增加在日文和中文里用到的雙字節(jié)字符的支持 (他們相對(duì)比較簡(jiǎn)單), 組合字符支持, 甚至也許對(duì)從右至左書寫的語言如希伯來文 (他們可不是那么簡(jiǎn)單的) 的支持. 但對(duì)這些高級(jí)功能的支持不應(yīng)該阻礙簡(jiǎn)單的平板 UTF-8 在 拉丁, 希臘, 斯拉夫和科學(xué)用符號(hào)方面的快速應(yīng)用, 以取代大量的歐洲 8 位編碼, 并提供一個(gè)象樣的科學(xué)用符號(hào)集.

    我該怎樣修改我的軟件?

    有兩種途徑可以支持 UTF-8, 我稱之為軟轉(zhuǎn)換與硬轉(zhuǎn)換. 軟轉(zhuǎn)換時(shí), 各處的數(shù)據(jù)均保存為 UTF-8 形式, 因而需要修改的軟件很少. 在硬轉(zhuǎn)換時(shí), 程序?qū)⒆x入的 UTF-8 數(shù)據(jù)轉(zhuǎn)換成寬字符數(shù)組, 以在應(yīng)用程序內(nèi)部處理. 在輸出時(shí), 再把字符串轉(zhuǎn)換回 UTF-8 形式.

    大多數(shù)應(yīng)用程序只用軟轉(zhuǎn)換就可以工作得很好了. 這使得將 UTF-8 引入 Unix 成為切實(shí)可行的. 例如, 象 cat 和 echo 這樣的程序根本不需要修改. 他們?nèi)匀豢梢詫?duì)輸入輸出的是 ISO 8859-2 還是 UTF-8 一無所知, 因?yàn)樗鼈冎皇前徇\(yùn)字節(jié)流而沒有處理它們. 它們只能識(shí)別 ASCII 字符和象 '\n' 這樣的控制碼, 而這在 UTF-8 下也沒有任何改變. 因此, 這些應(yīng)用程序的 UTF-8 編碼與解碼將完全在終端模擬器里完成.

    而那些通過數(shù)字節(jié)數(shù)來獲知字符數(shù)量的程序則需要一些小修改. 在 UTF-8 模式下, 它們必須不數(shù)入 0x80 到 0xBF 范圍內(nèi)的字節(jié), 因?yàn)檫@些只是跟隨字節(jié), 它們本身并不是字符. 例如, ls 程序就必須要修改, 因?yàn)樗ㄟ^數(shù)文件名中字符數(shù)來排放給用戶的目錄表格布局. 類似地, 所有的假定其輸出為定寬字體, 并因此而格式化它們的程序, 必須學(xué)會(huì)怎樣數(shù) UTF-8 文本中的字符數(shù). 編輯器的功能, 如刪除單個(gè)字符, 必須要作輕微的修改, 以刪除可能屬于該字符的所有字節(jié). 受影響有編輯器 (vi,emacs, 等等)以及使用 ncurses 庫的程序.

    Linux 核心使用軟轉(zhuǎn)換也可以工作得很好, 只需要非常微小的修改以支持 UTF-8. 大多數(shù)處理字符串的核心功能 (例如: 文件名, 環(huán)境變量, 等等) 都不受影響. 下列地方也許必須修改:

    • 控制臺(tái)顯示與鍵盤驅(qū)動(dòng)程序 (另一個(gè) VT100 模擬器) 必須能編碼和解碼 UTF-8, 必須要起碼支持 Unicode 字符集的幾個(gè)子集. 從 Linux 1.2 起這些功能已經(jīng)有了.
    • 外部文件系統(tǒng)驅(qū)動(dòng)程序, 例如 VFAT 和 WinNT 必須轉(zhuǎn)換文件名字符編碼. UTF-8 已經(jīng)加入可用的轉(zhuǎn)換選項(xiàng)的列表里了, 因此 mount 命令必須告訴核心驅(qū)動(dòng)程序用戶進(jìn)程希望看到 UTF-8 文件名. 既然 VFAT 和 WinNT 無論如何至少已經(jīng)用了 Unicode了, 那么 UTF-8 在這里就可以發(fā)揮其優(yōu)勢(shì), 以保證轉(zhuǎn)換中無信息損失.
    • POSIX 系統(tǒng)的 tty 驅(qū)動(dòng)程序支持一種 "cooked" 模式, 有一些原始的行編輯功能. 為了讓字符刪除功能工作正常, stty 必須在 tty 驅(qū)動(dòng)程序里設(shè)置 UTF-8 模式, 因此它就不會(huì)把 0x80 到 0xBF 范圍內(nèi)的跟隨字符也數(shù)進(jìn)去了. Bruno Haible 那里已經(jīng)有了一些 stty 和核心 tty 驅(qū)動(dòng) 程序的 Linux 補(bǔ)丁 了.

    C 對(duì) Unicode 和 UTF-8 的支持

    從 GNU glibc 2.1 開始, wchar_t 類型已經(jīng)正式定為只存放獨(dú)立于當(dāng)前 locale 的, 32位的 ISO 10646 值. glibc 2.2 開始將完全支持 ISO C 中的多字節(jié)轉(zhuǎn)換函數(shù) (wprintf(),mbstowcs(),等等), 這些函數(shù)可以用于在 wchar_t 和包括 UTF-8 在內(nèi)的任何依賴于 locale 的多字節(jié)編碼間進(jìn)行轉(zhuǎn)換.

    例如, 你可以寫

      wprintf(L"Sch鰊e Gre!\n");

    然后, 你的軟件將按照你的用戶在環(huán)境變量 LC_CTYPE (例如, en_US.UTF-8de_DE.ISO_8859-1) 中選擇的 locale 所指定的編碼來打印這段文字. 你的編譯器必須運(yùn)行在與該 C 源文件所用編碼相應(yīng)的 locale 中, 在目標(biāo)文件中以上的寬字符串將改為 wchar_t 字符串存儲(chǔ). 在輸出時(shí), 運(yùn)行時(shí)庫將把 wchar_t 字符串轉(zhuǎn)換回與程序執(zhí)行時(shí)的 locale 相應(yīng)的編碼.

    注意, 類似這樣的操作:

      char c = L"a"; 

    只允許從 U+0000 到 U+007F (7 位 ASCII) 范圍里的字符. 對(duì)于非 ASCII 字符, 不能直接從 wchar_tchar 轉(zhuǎn)換.

    現(xiàn)在, 象 readline() 這樣的函數(shù)在 UTF-8 locale 下也能工作了.

    怎樣激活 UTF-8 模式?

    如果你的應(yīng)用程序既支持 8 位字符集 (ISO 8859-*,KOI-8,等等), 也支持 UTF-8, 那么它必須通過某種方法以得知是否應(yīng)使用 UTF-8 模式. 幸運(yùn)的是, 在未來的幾年里, 人們將只使用 UTF-8, 因此你可以將它作為默認(rèn), 但即使如此, 你還是得既支持傳統(tǒng) 8 位字符集, 也支持 UTF-8.

    當(dāng)前的應(yīng)用程序使用許許多多的不同的命令行開關(guān)來激活它們各自的 UTF-8 模式, 例如:

    • xterm 命令行選項(xiàng) "-u8" 和 X resource "XTerm*utf8:1"
    • gnat/gcc 命令行選項(xiàng) "-gnatW8"
    • stty 命令行選項(xiàng) "iutf8"
    • mined 命令行選項(xiàng) "-U"
    • xemacs elisp 包裹 以在 UTF-8 和內(nèi)部使用的 MULE 編碼間轉(zhuǎn)換
    • vim 'fileencoding' 選項(xiàng)
    • less 環(huán)境變量 LESSCHARSET=utf-8

    記住每一個(gè)應(yīng)用程序的命令行選項(xiàng)或其他配置方法是非常單調(diào)乏味的, 因此急需某種標(biāo)準(zhǔn)方法.

    如果你在你的應(yīng)用程序里使用硬轉(zhuǎn)換, 并使用某種特定的 C 庫函數(shù)來處理外部字符編碼和內(nèi)部使用的 wchar_t 編碼的轉(zhuǎn)換工作, 那么 C 庫會(huì)幫你處理模式切換的問題. 你只需將環(huán)境變量 LC_CTYPE 設(shè)為正確的 locale, 例如, 如果你使用 UTF-8, 那就是en.UTF-8, 而如果是 Latin-1, 并需要英語的轉(zhuǎn)換, 則設(shè)為 en.ISO_8859-1.

    然而, 大多數(shù)現(xiàn)存軟件的維護(hù)者選擇用軟轉(zhuǎn)換來代替, 而不使用 libc 的寬字符函數(shù), 不僅因?yàn)樗鼈冞€未得到廣泛應(yīng)用, 還因?yàn)檫@會(huì)使得軟件進(jìn)行大規(guī)模修改. 在這種情況下, 你的應(yīng)用程序必須自己來獲知何時(shí)使用 UTF-8 模式. 一種方式是做以下工作:

    按照環(huán)境變量 LC_ALL, LC_CTYPE, LANG 的順序, 尋找第一個(gè)有值的變量. 如果該值包含 UTF-8 子串 (也許是小寫或沒有"-") 則默認(rèn)為 UTF-8 模式 (仍然可以用命令行開關(guān)來重設(shè)), 因?yàn)檫@個(gè)值可靠又恰當(dāng)?shù)刂甘玖?C 庫應(yīng)該使用一種 UTF-8 locale.

    提供一個(gè)命令行選項(xiàng) (或者如果是 X 客戶程序則用 X resource 的值) 將仍然是有用的, 可以用來重設(shè)由 LC_CTYPE 等環(huán)境變量指定的默認(rèn)值.

    我怎樣才能得到 UTF-8 版本的 xterm?

    XFree86 里帶的 xterm 版本最近已經(jīng)由 Thomas E. Dickey 加入了支持 UTF-8 的擴(kuò)展. 使用方法是, 獲取 xterm patch #119 (1999-10-16) 或更新版本, 用 "./configure --enable-wide-chars ; make" 來編譯, 然后用命令行選項(xiàng) -u8 來調(diào)用 xterm, 使它將輸入輸出轉(zhuǎn)換為 UTF-8. 在 UTF-8 模式里使用一個(gè) *-ISO10646-1 字體. 當(dāng)你在 ISO 8859-1 模式里時(shí)也可以使用 *-ISO10646-1 字體, 因?yàn)?ISO 10646-1 字體與 ISO 8859-1 字體是完全向后兼容的.

    新的支持 UTF-8 的 xterm 版本, 以及一些 ISO 10646-1 字體, 將被收錄入 XFree86 4.0 版里.

    xterm 支持組合字符嗎?

    Xterm 當(dāng)前只支持級(jí)別1的 ISO 10646-1, 就是說, 不提供組合字符的支持. 當(dāng)前, 組合字符將被當(dāng)作空格字符對(duì)待. xterm 將來的修訂版很有可能加入某些簡(jiǎn)單的組合字符支持, 就是僅僅將那個(gè)有一個(gè)或多個(gè)組合字符的基字符加粗 (logical OR-ing). 對(duì)于在基線以下的和在小字符上方的重音符來說, 這樣處理的結(jié)果還是可以接受的. 對(duì)于象泰國文字體那樣使用特別設(shè)計(jì)的加粗字符的文字, 這樣處理也能工作的很好. 然而, 對(duì)于某些字體里, 在較高的字符上方組合上的重音符, 特別是對(duì)于 "fixed" 字體族, 產(chǎn)生的結(jié)果就不完全令人滿意了. 因此, 在可用的地方, 應(yīng)該繼續(xù)優(yōu)先使用預(yù)作字符.

    xterm 支持半寬與全寬 CJK 字體嗎?

    Xterm 當(dāng)前只支持那種所有字形都等寬的 cell-spaced 的字體. 將來的修訂版很有可能為 CJK 語言加入半寬與全寬字符支持, 類似于 kterm 提供的那種. 如果選擇的普通字體是 X×Y 象素大小, 且寬字符模式是打開的, 那么 xterm 會(huì)試圖裝入另外的一個(gè) 2X×Y 象素大小的字體 (同樣的 XLFD, 只是 AVERAGE_WIDTH 屬性的值翻倍). 它會(huì)用這個(gè)字體來顯示所有在 Unicode Technical Report #11 里被分配了East Asian Wide (W)East Asian FullWidth (F) 寬度屬性的 Unicode 字符. 下面這個(gè) C 函數(shù)用來測(cè)試一個(gè) Unicode 字符是否是寬字符并需要用覆蓋兩個(gè)字符單元的字形來顯示:

      /* This function tests, whether the ISO 10646/Unicode character code
       * ucs belongs into the East Asian Wide (W) or East Asian FullWidth
       * (F) category as defined in Unicode Technical Report #11. In this
       * case, the terminal emulator should represent the character using a
       * a glyph from a double-wide font that covers two normal (Latin)
       * character cells. */
    
      int iswide(int ucs)
      {
        if (ucs < 0x1100)
          return 0;
    
        return
          (ucs >= 0x1100 && ucs <= 0x115f) || /* Hangul Jamo */
          (ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & ~0x0011) != 0x300a &&
           ucs != 0x303f) ||                     /* CJK ... Yi */
          (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
          (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
          (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
          (ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */
          (ucs >= 0xffe0 && ucs <= 0xffe6);
      }

    某些 C 庫也提供了函數(shù)

      #include <wchar.h>
      int wcwidth(wchar_t wc);
      int wcswidth(const wchar_t *pwcs, size_t n);

    用來測(cè)定該寬字符 wc 或由 pwcs 指向的字符串中的 n 個(gè)寬字符碼 (或者少于 n 個(gè)寬字符碼, 如果在 n 個(gè)寬字符碼之前遇到一個(gè)空寬字符的話) 所要求的列位置的數(shù)量. 這些函數(shù)定義在 Open Group 的 Single UNIX Specification 里. 一個(gè)拉丁/希臘/斯拉夫/等等的字符要求一個(gè)列位置, 一個(gè) CJK 象形文字要求兩個(gè), 而一個(gè)組合字符要求零個(gè).

    最終 xterm 是否會(huì)支持從右到左的書寫?

    此刻還沒有給 xterm 增加從右到左功能的計(jì)劃. 希伯來與阿拉伯用戶因此不得不靠應(yīng)用程序在將希伯來文與阿拉伯文字符串送到終端前按左方向翻轉(zhuǎn)它們, 換句話說, 雙向處理必須在應(yīng)用程序里完成, 而不是在 xterm 里. 至少, 希伯來與阿拉伯文在預(yù)作字形的可用性的形式上, 以及提示表格上的支持, 比 ISO 8859 要有所改進(jìn). 現(xiàn)在還遠(yuǎn)沒有決定 xterm 是否支持雙向文字以及該怎樣工作. ISO 6429 = ECMA-48Unicode bidi algorithm 都提供了可供選擇的開始點(diǎn). 也可以參考 ECMA Technical
    Report TR/53
    . Xterm 也不處理阿拉伯文, Hangul 或 印度文本的格式化算法, 而且現(xiàn)在還不太清楚在 VT100 模擬器里處理是否可行和值得, 或者應(yīng)該留給應(yīng)用軟件去處理. 如果你打算在你的應(yīng)用程序里支持雙向文字輸出, 看一下 FriBidi, Dov Grobgeld 的 Unicode 雙向算法的自由實(shí)現(xiàn).

    我在哪兒能找到 ISO 10646-1 X11 字體?

    在過去的幾個(gè)月里出現(xiàn)了相當(dāng)多的 X11 的 Unicode 字體, 并且還在快速增多.

    • Markus Kuhn 正和其他許多志愿者一起工作于手動(dòng)將舊的 -misc-fixed-*-iso8859-1 字體擴(kuò)展到覆蓋所有的歐洲字符表 (拉丁, 希臘, 斯拉夫, 國際音標(biāo)字母表. 數(shù)學(xué)與技術(shù)符號(hào), 某些字體里甚至有亞美尼亞語, 喬治亞語, 片假名等). 更多信息請(qǐng)參考 Unicode fonts and tools for X11 頁. 這些字體將與 XFree86 一起分發(fā). 例如字體
        -misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646-1
      

      (舊的 xterm 的 fixed 缺省字體的一個(gè)擴(kuò)展, 包括超過 3000 個(gè)字符) 已經(jīng)是 XFree86 3.9 snapshot 的一部分了.

    • Markus 也做好了 X11R6.4 distribution 里所有的 Adobe 和 B&H BDF 字體的 ISO 10646 版本. 這些字體已經(jīng)包含了全部 Postscript 字體表 (大約 30 個(gè)額外的字符, 大部分也被 CP1252 MS-Windows 使用, 如 smart quotes, dashes 等), 在 ISO 8859-1 編碼下是沒有的. 它們?cè)?ISO 10646-1 版本里是完全可用的.
    • XFree86 4.0 將攜帶一個(gè)集成的 TrueType 字體引擎, 這使得你的 X 應(yīng)用程序可以將任何 Apple/Microsoft 字體用于 ISO 10646-1 編碼.
    • 將來的 XFree86 版本很有可能從分發(fā)版中去除大多數(shù)舊的 BDF 字體, 取而代之的是 ISO 10646-1 編碼的版本. X 服務(wù)器則會(huì)增加一個(gè)自動(dòng)編碼轉(zhuǎn)換器, 只有當(dāng)舊的 8 位軟件請(qǐng)求一個(gè)類似于 ISO 8859-* 編碼的字體時(shí), 才虛擬地從 ISO 10646-1 字體文件中創(chuàng)建一個(gè)這樣的字體. 現(xiàn)代軟件應(yīng)該優(yōu)先地直接使用 ISO 10646-1 字體編碼.
    • ClearlyU (cu12) 是一個(gè)非常有用的 X11 的 12 點(diǎn)陣, 100 dpi 的 proportional ISO 10646-1 BDF 字體, 包含超過 3700 個(gè)字符, 由 Mark Leisher 提供 (樣例圖象).
    • Roman Czyborra 的 GNU Unicode font 項(xiàng)目工作于收集一個(gè)完整的與免費(fèi)的 8×16/16×16 pixel Unicode 字體. 目前已經(jīng)覆蓋了 34000 個(gè)字符.
    • etl-unicode 是一個(gè) ISO 10646-1 BDF 字體, 由 Primoz Peterlin 提供.

    Unicode X11 字體名字以 -ISO10646-1 結(jié)尾. 這個(gè) X 邏輯字體描述器 (X Logical Font Descriptor, XLFD) 的 CHARSET_REGISTRY 和 CHARSET_ENCODING 域里的值已經(jīng)為所有 Unicode 和 ISO 10646-1 的 16 位字體而正式地注冊(cè)了. 每個(gè) *-ISO10646-1 字體都包含了整個(gè) Unicode 字符集里的某幾個(gè)子集, 而用戶必須弄清楚他們選擇的字體覆蓋哪幾個(gè)他們需要的字符子集.

    *-ISO10646-1 字體通常也指定一個(gè) DEFAULT_CHAR 值, 指向一個(gè)非 Unicode 字形, 用來表示所有在該字體里不可用的字符 (通常是一個(gè)虛線框, 一個(gè) H 的大小, 位于 0x1F 或 0xFFFE). 這使得用戶至少能知道這兒有一個(gè)不支持的字符. xterm 用的小的定寬字體比如 6x13 等, 將永遠(yuǎn)無法覆蓋所有的 Unicode, 因?yàn)樵S多文字比如日本漢字只能用比歐洲用戶廣泛使用的大的象素尺寸才能表示. 歐洲使用的典型的 Unicode 字體將只包含大約 1000 到 3000 個(gè)字符的子集.

    我怎樣才能找出一個(gè) X 字體里有哪些字形?

    X 協(xié)議無法讓一個(gè)應(yīng)用程序方便地找出一個(gè) cell-spaced 字體提供哪些字形, 它沒有為字體提供這樣的量度. 因此 Mark LeisherErik van de Poel (Netscape) 指定了一個(gè)新的 _XFREE86_GLYPH_RANGES BDF 屬性, 告訴應(yīng)用程序該 BDF 字體實(shí)現(xiàn)了哪個(gè) Unicode 子集. Mark Leisher 提供了一些樣例代碼以產(chǎn)生并掃描這個(gè)屬性, 而 Xmbdfed 3.9 以及更高版本將自動(dòng)將其加入到由它產(chǎn)生的每個(gè) BDF 文件里.

    與 UTF-8 終端模擬器相關(guān)的問題是什么?

    VT100 終端模擬器接受 ISO 2022 (=ECMA-35) ESC 序列, 用于在不同的字符集間切換.

    UTF-8 在 ISO 2022 的意義里是一個(gè) "其他編碼系統(tǒng)" (參考 ECMA 35 的 15.4 節(jié)). UTF-8 是在 ISO 2022 SS2/SS3/G0/G1/G2/G3 世界之外的, 因此如果你從 ISO 2022 切換到 UTF-8, 所有的 SS2/SS3/G0/G1/G2/G3 狀態(tài)都變得沒有意義了, 直到你離開 UTF-8 并切換回 ISO 2022. UTF-8 是一個(gè)沒有國家的編碼, 也就是一個(gè)自我終結(jié)的短字節(jié)序列完全決定了它代表什么字符, 獨(dú)立于任何國家的切換. G0 與 G1 在 ISO 10646 里與在 ISO 8859-1 里相同, 而 G2/G3 在 ISO 10646 里不存在, 因?yàn)槿魏巫址加泄潭ǖ奈恢? 因而不會(huì)發(fā)聲切換. 在 UTF-8 模式下, 你的終端不會(huì)因?yàn)槟闩既坏匮b入一個(gè)二進(jìn)制文件而切換入一種奇怪圖形字符模式. 這使得一個(gè)終端在 UTF-8 模式下比在 ISO 2022 模式下要健壯得多, 而且因此可以有辦法將終端鎖在 UTF-8 模式里, 而不會(huì)偶然地回到 ISO 2022 世界里.

    ISO 2022 標(biāo)準(zhǔn)指定了一系列的 ESC % 序列, 以離開 ISO 2022 世界 (指定其他的編碼系統(tǒng), DOCS), 用于 UTF-8 的許多這樣的序列已經(jīng)注冊(cè)進(jìn)了 ISO 2375 International Register of Coded Character Sets:

    • ESC %G 從 ISO 2022 里激活一個(gè)未指定實(shí)現(xiàn)級(jí)別的 UTF-8 模式且允許再返回 ISO 2022.
    • ESC %@ 從 UTF-8 回到 ISO 2022, 條件是通過 ESC %G 進(jìn)入的 UTF-8
    • ESC %/G 切換進(jìn) UTF-8 級(jí)別 1 且不返回.
    • ESC %/H 切換進(jìn) UTF-8 級(jí)別 2 且不返回.
    • ESC %/I 切換進(jìn) UTF-8 級(jí)別 3 且不返回.

    當(dāng)一個(gè)終端模擬器在 UTF-8 模式時(shí), 任何 ISO 2022 逃脫碼序列例如用于切換 G2/G3 等的都被忽略. 一個(gè)在 UTF-8 模式下的終端模擬器唯一會(huì)執(zhí)行的 ISO 2022 序列是 ESC %@ 以從 UTF-8 返回 ISO 2022 方案.

    UTF-8 仍然允許你使用象 CSI 這樣的 C1 控制字符, 盡管 UTF-8 也使用 0x80-0x9F 范圍里的字節(jié). 重要的是必須理解在 UTF-8 模式下的終端模擬器必須在執(zhí)行任何控制字符前對(duì)收到的字節(jié)流運(yùn)用 UTF-8 解碼器. C1 字符與其他任何大于 U+007F 的字符一樣需先經(jīng)過 UTF-8 解碼.

    已經(jīng)有哪些支持 UTF-8 的應(yīng)用程序了?

    • YuditGaspar Sinai 的自由 X11 Unicode 編輯器
    • Mined 98Thomas Wolff 提供, 是一個(gè)可以處理 UTF-8 的文本編輯器.
    • less 版本 346 或更高, 支持 UTF-8
    • C-Kermit 7.0 在傳輸, 終端, 及文件字符集方面支持 UTF-8.
    • Sam 是 Plan9 的 UTF-8 編輯器, 類似于 vi, 也可用于 Linux 和 Win32. (Plan9 是第一個(gè)完全轉(zhuǎn)向 UTF-8, 將其作為字符編碼的操作系統(tǒng).)
    • 9termMatty Farrow 提供, 是一個(gè) Plan9 操作系統(tǒng)的 Unicode/UTF-8 終端模擬器的 Unix 移植.
    • Wily 是一個(gè) Plan9 Acme 編輯器的 Unix 實(shí)現(xiàn).
    • ucm-0.1Juliusz Chroboczek 的 Unicode 字符映射表, 一個(gè)小工具, 使你可以選中任何一個(gè) Unicode 字符并粘貼進(jìn)你的應(yīng)用程序.

    有哪些用于改善 UTF-8 支持的補(bǔ)丁?

    Postscript 字形的名字與 UCS 代碼是怎么關(guān)聯(lián)的?

    參考 Adobe 的 Unicode and Glyph Names 指南.

    X11 的剪切與粘貼工作在 UTF-8 時(shí)是如何完成的?

    參考 Juliusz Chroboczek客戶機(jī)間 Unicode 文本的交換 草案, 對(duì) ICCCM 的一個(gè)擴(kuò)充的建議, 用一個(gè)新的可用于屬性類型(property type)和選中(selection)目標(biāo)的原子 UTF8_STRING 來處理 UTF-8 的選中.

    現(xiàn)在有沒有用于處理 Unicode 的免費(fèi)的庫?

    各種 X widget 對(duì) Unicode 支持的現(xiàn)狀如何?

    有什么關(guān)于這個(gè)話題的好的郵件列表?

    你確實(shí)應(yīng)該訂閱的是 unicode@unicode.org 郵件列表, 這是發(fā)現(xiàn)標(biāo)準(zhǔn)的作者和其他許多領(lǐng)袖的話語的最好辦法. 訂閱方法是, 用 "subscribe" 作為標(biāo)題, "subscribe YOUR@EMAIL.ADDRESS unicode" 作為正文, 發(fā)一條消息到 unicode-request@unicode.org.

    也有一個(gè)專注與改進(jìn)通常用于 GNU/Linux 系統(tǒng)上應(yīng)用程序的 UTF-8 支持的郵件列表 linux-utf8@nl.linux.org. 訂閱方法是, 以 "subscribe linux-utf8" 為內(nèi)容, 發(fā)送消息到 majordomo@nl.linux.org. 你也可以瀏覽 linux-utf8 archive

    其他相關(guān)的還有 XFree86 組的 "字體" 與 "i18n" 列表, 但你必須成為一名正式的開發(fā)者才能訂閱.

    更多參考

    我不斷地將新的材料加入這份文檔, 因此請(qǐng)定期來查看. 歡迎所有關(guān)于改進(jìn)的建議, 以及自由軟件社區(qū)里關(guān)于改善 UTF-8 支持的廣告. UTF-8 用在 Linux 里是新近的事, 因此我們?cè)趯淼膸讉€(gè)月里可以見到大量的進(jìn)展.

    特別感謝 Ulrich Drepper 和 Bruno Haible 的有價(jià)值的注解

    Markus Kuhn <<Markus.Kuhn@cl.cam.ac.uk>
    創(chuàng)建于 1999-06-04 -- 最近更新于 2000-01-15 -- http://www.cl.cam.ac.uk/~mgk25/unicode.html

    posted on 2005-10-24 14:19 snoics 閱讀(418) 評(píng)論(0)  編輯  收藏 所屬分類: 它山之石
    主站蜘蛛池模板: 久久福利青草精品资源站免费 | 久久久久亚洲AV综合波多野结衣| 在线综合亚洲中文精品| 日本免费人成视频在线观看| 亚洲精品乱码久久久久久久久久久久| 亚欧国产一级在线免费| 亚洲真人日本在线| 国产在线观看无码免费视频| 亚洲精品无码久久久久| 日韩免费无码一区二区三区| 亚洲日本乱码一区二区在线二产线 | 国产精品亚洲а∨无码播放不卡| 国产乱子影视频上线免费观看| 国产天堂亚洲国产碰碰| 亚洲精品A在线观看| 91成人免费观看在线观看| 久久精品亚洲一区二区| 57pao国产成视频免费播放| 亚洲成人动漫在线观看| 毛片免费全部免费观看| 在线播放亚洲精品| 亚洲中文字幕无码久久综合网| 久久精品国产这里是免费| 亚洲欧洲视频在线观看| 日本黄页网站免费| 亚洲日韩在线观看免费视频| 亚洲AV日韩AV永久无码免下载| 亚洲免费观看网站| 亚洲色丰满少妇高潮18p| 亚洲视频在线一区二区| 最近中文字幕国语免费完整| 亚洲色无码国产精品网站可下载| 亚洲Av无码乱码在线观看性色| 暖暖日本免费中文字幕| 中文文字幕文字幕亚洲色| 中文字幕亚洲一区二区va在线| 亚洲成年人免费网站| 添bbb免费观看高清视频| 亚洲一区二区成人| 国产精品麻豆免费版| 99久久免费看国产精品|