• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            浪跡天涯

            唯有努力...
            努力....再努力...

            gbk, gb2312,big5,unicode,utf-8,utf-16之間的關系

            最近和同事討論unicode的相關知識,同事說unicode指utf-16,和utf-8相區別;而我的理解是unicode只是一種規范,而utf-16,utf-8等都是它的具體實現,互相也說不準。于是在網上搜索資料,最后發現其實雙方都有道理,只是個人理解不一樣罷了,的確通常來說的unicode是指utf-16的實現方式。這下面是搜索到的資料:

            以前收藏的一篇

            標題 談談Unicode編碼,簡要解釋UCS、UTF、BMP、BOM等名詞 選擇自 fmddlmyy 的 Blog
            關鍵字 談談Unicode編碼,簡要解釋UCS、UTF、BMP、BOM等名詞

            這是一篇程序員寫給程序員的趣味讀物。所謂趣味是指可以比較輕松地了解一些原來不清楚的概念,增進知識,類似于打RPG游戲的升級。整理這篇文章的動機是兩個問題:

            問題一:
            使用Windows記事本的“另存為”,可以在GBK、Unicode、Unicode big endian和UTF-8這幾種編碼方式間相互轉換。同樣是txt文件,Windows是怎樣識別編碼方式的呢?

            我很早前就發現Unicode、Unicode big endian和UTF-8編碼的txt文件的開頭會多出幾個字節,分別是FF、FE(Unicode),FE、FF(Unicode big endian),EF、BB、BF(UTF-8)。但這些標記是基于什么標準呢?

            問題二:
            最近在網上看到一個ConvertUTF.c,實現了UTF-32、UTF-16和UTF-8這三種編碼方式的相互轉換。對于Unicode(UCS2)、GBK、UTF-8這些編碼方式,我原來就了解。但這個程序讓我有些糊涂,想不起來UTF-16和UCS2有什么關系。
            查了查相關資料,總算將這些問題弄清楚了,順帶也了解了一些Unicode的細節。寫成一篇文章,送給有過類似疑問的朋友。本文在寫作時盡量做到通俗易懂,但要求讀者知道什么是字節,什么是十六進制。

            0、big endian和little endian
            big endian和little endian是CPU處理多字節數的不同方式。例如“漢”字的Unicode編碼是6C49。那么寫到文件里時,究竟是將6C寫在前面,還是將49寫在前面?如果將6C寫在前面,就是big endian。還是將49寫在前面,就是little endian。

            “endian”這個詞出自《格列佛游記》。小人國的內戰就源于吃雞蛋時是究竟從大頭(Big-Endian)敲開還是從小頭(Little-Endian)敲開,由此曾發生過六次叛亂,其中一個皇帝送了命,另一個丟了王位。

            我們一般將endian翻譯成“字節序”,將big endian和little endian稱作“大尾”和“小尾”。

            1、字符編碼、內碼,順帶介紹漢字編碼
            字符必須編碼后才能被計算機處理。計算機使用的缺省編碼方式就是計算機的內碼。早期的計算機使用7位的ASCII編碼,為了處理漢字,程序員設計了用于簡體中文的GB2312和用于繁體中文的big5。

            GB2312(1980年)一共收錄了7445個字符,包括6763個漢字和682個其它符號。漢字區的內碼范圍高字節從B0-F7,低字節從A1-FE,占用的碼位是72*94=6768。其中有5個空位是D7FA-D7FE。

            GB2312支持的漢字太少。1995年的漢字擴展規范GBK1.0收錄了21886個符號,它分為漢字區和圖形符號區。漢字區包括21003個字符。2000年的GB18030是取代GBK1.0的正式國家標準。該標準收錄了27484個漢字,同時還收錄了藏文、蒙文、維吾爾文等主要的少數民族文字。現在的PC平臺必須支持GB18030,對嵌入式產品暫不作要求。所以手機、MP3一般只支持GB2312。

            從ASCII、GB2312、GBK到GB18030,這些編碼方法是向下兼容的,即同一個字符在這些方案中總是有相同的編碼,后面的標準支持更多的字符。在這些編碼中,英文和中文可以統一地處理。區分中文編碼的方法是高字節的最高位不為0。按照程序員的稱呼,GB2312、GBK到GB18030都屬于雙字節字符集 (DBCS)。

            有的中文Windows的缺省內碼還是GBK,可以通過GB18030升級包升級到GB18030。不過GB18030相對GBK增加的字符,普通人是很難用到的,通常我們還是用GBK指代中文Windows內碼。

            這里還有一些細節:

            GB2312的原文還是區位碼,從區位碼到內碼,需要在高字節和低字節上分別加上A0。

            在DBCS中,GB內碼的存儲格式始終是big endian,即高位在前。

            GB2312的兩個字節的最高位都是1。但符合這個條件的碼位只有128*128=16384個。所以GBK和GB18030的低字節最高位都可能不是1。不過這不影響DBCS字符流的解析:在讀取DBCS字符流時,只要遇到高位為1的字節,就可以將下兩個字節作為一個雙字節編碼,而不用管低字節的高位是什么。

            2、Unicode、UCS和UTF
            前面提到從ASCII、GB2312、GBK到GB18030的編碼方法是向下兼容的。而Unicode只與ASCII兼容(更準確地說,是與ISO-8859-1兼容),與GB碼不兼容。例如“漢”字的Unicode編碼是6C49,而GB碼是BABA。

            Unicode也是一種字符編碼方法,不過它是由國際組織設計,可以容納全世界所有語言文字的編碼方案。Unicode的學名是"Universal Multiple-Octet Coded Character Set",簡稱為UCS。UCS可以看作是"Unicode Character Set"的縮寫。

            根據維基百科全書(http://zh.wikipedia.org/wiki/)的記載:歷史上存在兩個試圖獨立設計Unicode的組織,即國際標準化組織(ISO)和一個軟件制造商的協會(unicode.org)。ISO開發了ISO 10646項目,Unicode協會開發了Unicode項目。

            在1991年前后,雙方都認識到世界不需要兩個不兼容的字符集。于是它們開始合并雙方的工作成果,并為創立一個單一編碼表而協同工作。從Unicode2.0開始,Unicode項目采用了與ISO 10646-1相同的字庫和字碼。

            目前兩個項目仍都存在,并獨立地公布各自的標準。Unicode協會現在的最新版本是2005年的Unicode 4.1.0。ISO的最新標準是10646-3:2003。

            UCS規定了怎么用多個字節表示各種文字。怎樣傳輸這些編碼,是由UTF(UCS Transformation Format)規范規定的,常見的UTF規范包括UTF-8、UTF-7、UTF-16。

            IETF的RFC2781和RFC3629以RFC的一貫風格,清晰、明快又不失嚴謹地描述了UTF-16和UTF-8的編碼方法。我總是記不得IETF是Internet Engineering Task Force的縮寫。但IETF負責維護的RFC是Internet上一切規范的基礎。

            3、UCS-2、UCS-4、BMP

            UCS有兩種格式:UCS-2和UCS-4。顧名思義,UCS-2就是用兩個字節編碼,UCS-4就是用4個字節(實際上只用了31位,最高位必須為0)編碼。下面讓我們做一些簡單的數學游戲:

            UCS-2有2^16=65536個碼位,UCS-4有2^31=2147483648個碼位。

            UCS-4根據最高位為0的最高字節分成2^7=128個group。每個group再根據次高字節分為256個plane。每個plane根據第3個字節分為256行 (rows),每行包含256個cells。當然同一行的cells只是最后一個字節不同,其余都相同。

            group 0的plane 0被稱作Basic Multilingual Plane, 即BMP。或者說UCS-4中,高兩個字節為0的碼位被稱作BMP。

            將UCS-4的BMP去掉前面的兩個零字節就得到了UCS-2。在UCS-2的兩個字節前加上兩個零字節,就得到了UCS-4的BMP。而目前的UCS-4規范中還沒有任何字符被分配在BMP之外。

            4、UTF編碼

            UTF-8就是以8位為單元對UCS進行編碼。從UCS-2到UTF-8的編碼方式如下:

            UCS-2編碼(16進制) UTF-8 字節流(二進制)
            0000 - 007F 0xxxxxxx
            0080 - 07FF 110xxxxx 10xxxxxx
            0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx

            例如“漢”字的Unicode編碼是6C49。6C49在0800-FFFF之間,所以肯定要用3字節模板了:1110xxxx 10xxxxxx 10xxxxxx。將6C49寫成二進制是:0110 110001 001001, 用這個比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。

            讀者可以用記事本測試一下我們的編碼是否正確。

            UTF-16以16位為單元對UCS進行編碼。對于小于0x10000的UCS碼,UTF-16編碼就等于UCS碼對應的16位無符號整數。對于不小于0x10000的UCS碼,定義了一個算法。不過由于實際使用的UCS2,或者UCS4的BMP必然小于0x10000,所以就目前而言,可以認為UTF-16和UCS-2基本相同。但UCS-2只是一個編碼方案,UTF-16卻要用于實際的傳輸,所以就不得不考慮字節序的問題。

            5、UTF的字節序和BOM
            UTF-8以字節為編碼單元,沒有字節序的問題。UTF-16以兩個字節為編碼單元,在解釋一個UTF-16文本前,首先要弄清楚每個編碼單元的字節序。例如收到一個“奎”的Unicode編碼是594E,“乙”的Unicode編碼是4E59。如果我們收到UTF-16字節流“594E”,那么這是“奎”還是“乙”?

            Unicode規范中推薦的標記字節順序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一個有點小聰明的想法:

            在UCS編碼中有一個叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的編碼是FEFF。而FFFE在UCS中是不存在的字符,所以不應該出現在實際傳輸中。UCS規范建議我們在傳輸字節流前,先傳輸字符"ZERO WIDTH NO-BREAK SPACE"。

            這樣如果接收者收到FEFF,就表明這個字節流是Big-Endian的;如果收到FFFE,就表明這個字節流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被稱作BOM。

            UTF-8不需要BOM來表明字節順序,但可以用BOM來表明編碼方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF(讀者可以用我們前面介紹的編碼方法驗證一下)。所以如果接收者收到以EF BB BF開頭的字節流,就知道這是UTF-8編碼了。

            Windows就是使用BOM來標記文本文件的編碼方式的。

            6、進一步的參考資料
            本文主要參考的資料是 "Short overview of ISO-IEC 10646 and Unicode" (http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html)。

            我還找了兩篇看上去不錯的資料,不過因為我開始的疑問都找到了答案,所以就沒有看:

            "Understanding Unicode A general introduction to the Unicode Standard" (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-Chapter04a)
            "Character set encoding basics Understanding character set encodings and legacy encodings" (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-Chapter03)
            我寫過UTF-8、UCS-2、GBK相互轉換的軟件包,包括使用Windows API和不使用Windows API的版本。以后有時間的話,我會整理一下放到我的個人主頁上(http://fmddlmyy.home4u.china.com/)。



            Unicode,GBK,GB2312,UTF-8概念基礎
            本部分采用重用,轉載一篇文章來完成這部分的目標。
            來源:holen'blog   對字符編碼與Unicode,ISO 10646,UCS,UTF8,UTF16,GBK,GB2312的理解
            地址:http://blog.donews.com/holen/archive/2004/11/30/188182.aspx
             
            Unicode:

            unicode.org制定的編碼機制, 要將全世界常用文字都函括進去.
            在1.0中是16位編碼, 由U+0000到U+FFFF. 每個2byte碼對應一個字符; 在2.0開始拋棄了16位限制, 原來的16位作為基本位平面, 另外增加了16個位平面, 相當于20位編碼, 編碼范圍0到0x10FFFF.

            UCS:

            ISO制定的ISO10646標準所定義的 Universal Character Set, 采用4byte編碼.

            Unicode與UCS的關系:

            ISO與unicode.org是兩個不同的組織, 因此最初制定了不同的標準; 但自從unicode2.0開始, unicode采用了與ISO 10646-1相同的字庫和字碼, ISO也承諾ISO10646將不會給超出0x10FFFF的UCS-4編碼賦值, 使得兩者保持一致.

            UCS的編碼方式:

          1. UCS-2, 與unicode的2byte編碼基本一樣.
          2. UCS-4, 4byte編碼, 目前是在UCS-2前加上2個全零的byte.

            UTF: Unicode/UCS Transformation Format
          3. UTF-8, 8bit編碼, ASCII不作變換, 其他字符做變長編碼, 每個字符1-3 byte. 通常作為外碼. 有以下優點:
            * 與CPU字節順序無關, 可以在不同平臺之間交流
            * 容錯能力高, 任何一個字節損壞后, 最多只會導致一個編碼碼位損失, 不會鏈鎖錯誤(如GB碼錯一個字節就會整行亂碼)
          4. UTF-16, 16bit編碼, 是變長碼, 大致相當于20位編碼, 值在0到0x10FFFF之間, 基本上就是unicode編碼的實現. 它是變長碼, 與CPU字序有關, 但因為最省空間, 常作為網絡傳輸的外碼.
            UTF-16是unicode的preferred encoding.
          5. UTF-32, 僅使用了unicode范圍(0到0x10FFFF)的32位編碼, 相當于UCS-4的子集.

            UTF與unicode的關系:

            Unicode是一個字符集, 可以看作為內碼.
            而UTF是一種編碼方式, 它的出現是因為unicode不適宜在某些場合直接傳輸和處理. UTF-16直接就是unicode編碼, 沒有變換, 但它包含了0x00在編碼內, 頭256字節碼的第一個byte都是0x00, 在操作系統(C語言)中有特殊意義, 會引起問題. 采用UTF-8編碼對unicode的直接編碼作些變換可以避免這問題, 并帶來一些優點.

            中國國標編碼:
          6. GB 13000: 完全等同于ISO 10646-1/Unicode 2.1, 今后也將隨ISO 10646/Unicode的標準更改而同步更改.
          7. GBK: 對GB2312的擴充, 以容納GB2312字符集范圍以外的Unicode 2.1的統一漢字部分, 并且增加了部分unicode中沒有的字符.
          8. GB 18030-2000: 基于GB 13000, 作為Unicode 3.0的GBK擴展版本, 覆蓋了所有unicode編碼, 地位等同于UTF-8, UTF-16, 是一種unicode編碼形式. 變長編碼, 用單字節/雙字節/4字節對字符編碼. GB18030向下兼容GB2312/GBK.
            GB 18030是中國所有非手持/嵌入式計算機系統的強制實施標準.


            -------------------------------


             

            什么是 UCS 和 ISO 10646?

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

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

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

            UCS 不僅給每個字符分配一個代碼, 而且賦予了一個正式的名字. 表示一個 UCS 或 Unicode 值的十六進制數, 通常在前面加上 "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, 已經 BMP 以外的大范圍的編碼是為私用保留的.

            什么是組合字符?

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

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

            什么是 UCS 實現級別?

            不是所有的系統都需要支持象組合字符這樣的 UCS 里所有的先進機制. 因此 ISO 10646 指定了下列三種實現級別:

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

            什么是 Unicode?

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

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

            Unicode 協會公布的 Unicode 標準 嚴密地包含了 ISO 10646-1 實現級別3的基本多語言面. 在兩個標準里所有的字符都在相同的位置并且有相同的名字.

            Unicode 標準額外定義了許多與字符有關的語義符號學, 一般而言是對于實現高質量的印刷出版系統的更好的參考. Unicode 詳細說明了繪制某些語言(比如阿拉伯語)表達形式的算法, 處理雙向文字(比如拉丁與希伯來文混合文字)的算法和 排序與字符串比較 所需的算法, 以及其他許多東西.

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

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

            什么是 UTF-8?

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

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

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

            UTF-8 有一下特性:

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

            下列字節串用來表示一個字符. 用到哪個串取決于該字符在 Unicode 中的序號.

            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 的位置由字符編碼數的二進制表示的位填入. 越靠右的 x 具有越少的特殊意義. 只用最短的那個足夠表達一個字符編碼數的多字節串. 注意在多字節串中, 第一個字節的開頭"1"的數目就是整個串中字節的數目.

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

            11000010 10101001 = 0xC2 0xA9

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

            11100010 10001001 10100000 = 0xE2 0x89 0xA0

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

            什么編程語言支持 Unicode?

            在大約 1993 年之后開發的大多數現代編程語言都有一個特別的數據類型, 叫做 Unicode/ISO 10646-1 字符. 在 Ada95 中叫 Wide_Character, 在 Java 中叫 char.

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


            附錄1 再說說區位碼、GB2312、內碼和代碼頁
            有的朋友對文章中這句話還有疑問:
            “GB2312的原文還是區位碼,從區位碼到內碼,需要在高字節和低字節上分別加上A0。”

            我再詳細解釋一下:

            “GB2312的原文”是指國家1980年的一個標準《中華人民共和國國家標準 信息交換用漢字編碼字符集 基本集 GB 2312-80》。這個標準用兩個數來編碼漢字和中文符號。第一個數稱為“區”,第二個數稱為“位”。所以也稱為區位碼。1-9區是中文符號,16-55區是一級漢字,56-87區是二級漢字。現在Windows也還有區位輸入法,例如輸入1601得到“啊”。(這個區位輸入法可以自動識別16進制的GB2312和10進制的區位碼,也就是說輸入B0A1同樣會得到“啊”。)

            內碼是指操作系統內部的字符編碼。早期操作系統的內碼是與語言相關的。現在的Windows在系統內部支持Unicode,然后用代碼頁適應各種語言,“內碼”的概念就比較模糊了。微軟一般將缺省代碼頁指定的編碼說成是內碼。

            內碼這個詞匯,并沒有什么官方的定義,代碼頁也只是微軟這個公司的叫法。作為程序員,我們只要知道它們是什么東西,沒有必要過多地考證這些名詞。

            所謂代碼頁(code page)就是針對一種語言文字的字符編碼。例如GBK的code page是CP936,BIG5的code page是CP950,GB2312的code page是CP20936。

            Windows中有缺省代碼頁的概念,即缺省用什么編碼來解釋字符。例如Windows的記事本打開了一個文本文件,里面的內容是字節流:BA、BA、D7、D6。Windows應該去怎么解釋它呢?

            是按照Unicode編碼解釋、還是按照GBK解釋、還是按照BIG5解釋,還是按照ISO8859-1去解釋?如果按GBK去解釋,就會得到“漢字”兩個字。按照其它編碼解釋,可能找不到對應的字符,也可能找到錯誤的字符。所謂“錯誤”是指與文本作者的本意不符,這時就產生了亂碼。

            答案是Windows按照當前的缺省代碼頁去解釋文本文件里的字節流。缺省代碼頁可以通過控制面板的區域選項設置。記事本的另存為中有一項ANSI,其實就是按照缺省代碼頁的編碼方法保存。

            Windows的內碼是Unicode,它在技術上可以同時支持多個代碼頁。只要文件能說明自己使用什么編碼,用戶又安裝了對應的代碼頁,Windows就能正確顯示,例如在HTML文件中就可以指定charset。

            有的HTML文件作者,特別是英文作者,認為世界上所有人都使用英文,在文件中不指定charset。如果他使用了0x80-0xff之間的字符,中文Windows又按照缺省的GBK去解釋,就會出現亂碼。這時只要在這個html文件中加上指定charset的語句,例如:
            <meta http-equiv="Content-Type" content="text/html; charset=ISO8859-1">
            如果原作者使用的代碼頁和ISO8859-1兼容,就不會出現亂碼了。

            再說區位碼,啊的區位碼是1601,寫成16進制是0x10,0x01。這和計算機廣泛使用的ASCII編碼沖突。為了兼容00-7f的ASCII編碼,我們在區位碼的高、低字節上分別加上A0。這樣“啊”的編碼就成為B0A1。我們將加過兩個A0的編碼也稱為GB2312編碼,雖然GB2312的原文根本沒提到這一點。


            字符編碼筆記:ASCII,Unicode和UTF-8


             

            今天中午,我突然想搞清楚Unicode和UTF-8之間的關系,于是就開始在網上查資料。

            結果,這個問題比我想象的復雜,從午飯后一直看到晚上9點,才算初步搞清楚。

            下面就是我的筆記,主要用來整理自己的思路。但是,我盡量試圖寫得通俗易懂,希望能對其他朋友有用。畢竟,字符編碼是計算機技術的基石,想要熟練使用計算機,就必須懂得一點字符編碼的知識。

            1. ASCII碼

            我們知道,在計算機內部,所有的信息最終都表示為一個二進制的字符串。每一個二進制位(bit)有0和1兩種狀態,因此八個二進制位就可以組合出256種狀態,這被稱為一個字節(byte)。也就是說,一個字節一共可以用來表示256種不同的狀態,每一個狀態對應一個符號,就是256個符號,從0000000到11111111。

            上個世紀60年代,美國制定了一套字符編碼,對英語字符與二進制位之間的關系,做了統一規定。這被稱為ASCII碼,一直沿用至今。

            ASCII碼一共規定了128個字符的編碼,比如空格“SPACE”是32(二進制00100000),大寫的字母A是65(二進制01000001)。這128個符號(包括32個不能打印出來的控制符號),只占用了一個字節的后面7位,最前面的1位統一規定為0。

            2、非ASCII編碼

            英語用128個符號編碼就夠了,但是用來表示其他語言,128個符號是不夠的。比如,在法語中,字母上方有注音符號,它就無法用ASCII碼表示。于是,一些歐洲國家就決定,利用字節中閑置的最高位編入新的符號。比如,法語中的é的編碼為130(二進制10000010)。這樣一來,這些歐洲國家使用的編碼體系,可以表示最多256個符號。

            但是,這里又出現了新的問題。不同的國家有不同的字母,因此,哪怕它們都使用256個符號的編碼方式,代表的字母卻不一樣。比如,130在法語編碼中代表了é,在希伯來語編碼中卻代表了字母Gimel (?),在俄語編碼中又會代表另一個符號。但是不管怎樣,所有這些編碼方式中,0—127表示的符號是一樣的,不一樣的只是128—255的這一段。

            至于亞洲國家的文字,使用的符號就更多了,漢字就多達10萬左右。一個字節只能表示256種符號,肯定是不夠的,就必須使用多個字節表達一個符號。比如,簡體中文常見的編碼方式是GB2312,使用兩個字節表示一個漢字,所以理論上最多可以表示256x256=65536個符號。

            中文編碼的問題需要專文討論,這篇筆記不涉及。這里只指出,雖然都是用多個字節表示一個符號,但是GB類的漢字編碼與后文的Unicode和UTF-8是毫無關系的。

            3.Unicode

            正如上一節所說,世界上存在著多種編碼方式,同一個二進制數字可以被解釋成不同的符號。因此,要想打開一個文本文件,就必須知道它的編碼方式,否則用錯誤的編碼方式解讀,就會出現亂碼。為什么電子郵件常常出現亂碼?就是因為發信人和收信人使用的編碼方式不一樣。

            可以想象,如果有一種編碼,將世界上所有的符號都納入其中。每一個符號都給予一個獨一無二的編碼,那么亂碼問題就會消失。這就是Unicode,就像它的名字都表示的,這是一種所有符號的編碼。

            Unicode當然是一個很大的集合,現在的規模可以容納100多萬個符號。每個符號的編碼都不一樣,比如,U+0639表示阿拉伯字母Ain,U+0041表示英語的大寫字母A,U+4E25表示漢字“嚴”。具體的符號對應表,可以查詢unicode.org,或者專門的漢字對應表

            4. Unicode的問題

            需要注意的是,Unicode只是一個符號集,它只規定了符號的二進制代碼,卻沒有規定這個二進制代碼應該如何存儲。

            比如,漢字“嚴”的unicode是十六進制數4E25,轉換成二進制數足足有15位(100111000100101),也就是說這個符號的表示至少需要2個字節。表示其他更大的符號,可能需要3個字節或者4個字節,甚至更多。

            這里就有兩個嚴重的問題,第一個問題是,如何才能區別unicode和ascii?計算機怎么知道三個字節表示一個符號,而不是分別表示三個符號呢?第二個問題是,我們已經知道,英文字母只用一個字節表示就夠了,如果unicode統一規定,每個符號用三個或四個字節表示,那么每個英文字母前都必然有二到三個字節是0,這對于存儲來說是極大的浪費,文本文件的大小會因此大出二三倍,這是無法接受的。

            它們造成的結果是:1)出現了unicode的多種存儲方式,也就是說有許多種不同的二進制格式,可以用來表示unicode。2)unicode在很長一段時間內無法推廣,直到互聯網的出現。

            5.UTF-8

            互聯網的普及,強烈要求出現一種統一的編碼方式。UTF-8就是在互聯網上使用最廣的一種unicode的實現方式。其他實現方式還包括UTF-16和UTF-32,不過在互聯網上基本不用。重復一遍,這里的關系是,UTF-8是Unicode的實現方式之一。

            UTF-8最大的一個特點,就是它是一種變長的編碼方式。它可以使用1~4個字節表示一個符號,根據不同的符號而變化字節長度。

            UTF-8的編碼規則很簡單,只有二條:

            1)對于單字節的符號,字節的第一位設為0,后面7位為這個符號的unicode碼。因此對于英語字母,UTF-8編碼和ASCII碼是相同的。

            2)對于n字節的符號(n>1),第一個字節的前n位都設為1,第n+1位設為0,后面字節的前兩位一律設為10。剩下的沒有提及的二進制位,全部為這個符號的unicode碼。

            下表總結了編碼規則,字母x表示可用編碼的位。

            Unicode符號范圍 | UTF-8編碼方式
            (十六進制) | (二進制)
            --------------------+---------------------------------------------
            0000 0000-0000 007F | 0xxxxxxx
            0000 0080-0000 07FF | 110xxxxx 10xxxxxx
            0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
            0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

            下面,還是以漢字“嚴”為例,演示如何實現UTF-8編碼。

            已知“嚴”的unicode是4E25(100111000100101),根據上表,可以發現4E25處在第三行的范圍內(0000 0800-0000 FFFF),因此“嚴”的UTF-8編碼需要三個字節,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然后,從“嚴”的最后一個二進制位開始,依次從后向前填入格式中的x,多出的位補0。這樣就得到了,“嚴”的UTF-8編碼是“11100100 10111000 10100101”,轉換成十六進制就是E4B8A5。

            6. Unicode與UTF-8之間的轉換

            通過上一節的例子,可以看到“嚴”的Unicode碼是4E25,UTF-8編碼是E4B8A5,兩者是不一樣的。它們之間的轉換可以通過程序實現。

            在Windows平臺下,有一個最簡單的轉化方法,就是使用內置的記事本小程序Notepad.exe。打開文件后,點擊“文件”菜單中的“另存為”命令,會跳出一個對話框,在最底部有一個“編碼”的下拉條。

            里面有四個選項:ANSI,Unicode,Unicode big endian 和 UTF-8。

            1)ANSI是默認的編碼方式。對于英文文件是ASCII編碼,對于簡體中文文件是GB2312編碼(只針對Windows簡體中文版,如果是繁體中文版會采用Big5碼)。

            2)Unicode編碼指的是UCS-2編碼方式,即直接用兩個字節存入字符的Unicode碼。這個選項用的little endian格式。

            3)Unicode big endian編碼與上一個選項相對應。我在下一節會解釋little endian和big endian的涵義。

            4)UTF-8編碼,也就是上一節談到的編碼方法。

            選擇完”編碼方式“后,點擊”保存“按鈕,文件的編碼方式就立刻轉換好了。

            7. Little endian和Big endian

            上一節已經提到,Unicode碼可以采用UCS-2格式直接存儲。以漢字”嚴“為例,Unicode碼是4E25,需要用兩個字節存儲,一個字節是4E,另一個字節是25。存儲的時候,4E在前,25在后,就是Big endian方式;25在前,4E在后,就是Little endian方式。

            這兩個古怪的名稱來自英國作家斯威夫特的《格列佛游記》。在該書中,小人國里爆發了內戰,戰爭起因是人們爭論,吃雞蛋時究竟是從大頭(Big-Endian)敲開還是從小頭(Little-Endian)敲開。為了這件事情,前后爆發了六次戰爭,一個皇帝送了命,另一個皇帝丟了王位。

            因此,第一個字節在前,就是”大頭方式“(Big endian),第二個字節在前就是”小頭方式“(Little endian)。

            那么很自然的,就會出現一個問題:計算機怎么知道某一個文件到底采用哪一種方式編碼?

            Unicode規范中定義,每一個文件的最前面分別加入一個表示編碼順序的字符,這個字符的名字叫做”零寬度非換行空格“(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。這正好是兩個字節,而且FF比FE大1。

            如果一個文本文件的頭兩個字節是FE FF,就表示該文件采用大頭方式;如果頭兩個字節是FF FE,就表示該文件采用小頭方式。

            8. 實例

            下面,舉一個實例。

            打開”記事本“程序Notepad.exe,新建一個文本文件,內容就是一個”嚴“字,依次采用ANSI,Unicode,Unicode big endian 和 UTF-8編碼方式保存。

            然后,用文本編輯軟件UltraEdit中的”十六進制功能“,觀察該文件的內部編碼方式。

            1)ANSI:文件的編碼就是兩個字節“D1 CF”,這正是“嚴”的GB2312編碼,這也暗示GB2312是采用大頭方式存儲的。

            2)Unicode:編碼是四個字節“FF FE 25 4E”,其中“FF FE”表明是小頭方式存儲,真正的編碼是4E25。

            3)Unicode big endian:編碼是四個字節“FE FF 4E 25”,其中“FE FF”表明是大頭方式存儲。

            4)UTF-8:編碼是六個字節“EF BB BF E4 B8 A5”,前三個字節“EF BB BF”表示這是UTF-8編碼,后三個“E4B8A5”就是“嚴”的具體編碼,它的存儲順序與編碼順序是一致的。

            9. 延伸閱讀

            * The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets(關于字符集的最基本知識)

            * 談談Unicode編碼

            * RFC3629:UTF-8, a transformation format of ISO 10646(如果實現UTF-8的規定)

          9. posted on 2008-01-24 09:36 浪跡天涯 閱讀(13749) 評論(4)  編輯 收藏 引用 所屬分類: Other

            評論

            # re: gbk, gb2312,big5,unicode,utf-8,utf-16之間的關系 2008-01-24 10:07 浪跡天涯

            那么既然統一了編碼,如何兼容原先各國的文字編碼呢?


              這個時候就需要codepage了。


              什么是codepage?codepage就是各國的文字編碼和Unicode之間的映射表。


              比如簡體中文和Unicode的映射表就是CP936,點這里查看官方的映射表。


              以下是幾個常用的codepage,相應的修改上面的地址的數字即可。


              codepage=936 簡體中文GBK


              codepage=950 繁體中文BIG5


              codepage=437 美國/加拿大英語


              codepage=932 日文


              codepage=949 韓文


              codepage=866 俄文


              codepage=65001 Unicode UFT-8


              最后一個65001,據個人理解,應該只是一個虛擬的映射表,實際只是一個算法而已。


              從936中隨意取一行,例如:


              0x9993 0x6ABD #CJK UNIFIED IDEOGRAPH


              前面的編碼是GBK的編碼,后面的是Unicode。
              回復  更多評論   

            # re: gbk, gb2312,big5,unicode,utf-8,utf-16之間的關系 2010-07-09 17:06 TerryEVANS

            I strictly recommend not to wait until you earn enough amount of cash to order goods! You can take the <a href="http://bestfinance-blog.com">loan</a> or just short term loan and feel comfortable   回復  更多評論   

            # re: gbk, gb2312,big5,unicode,utf-8,utf-16之間的關系 2010-07-18 13:38 custom term papers

            I state that college students must look through the character essays they purchase from buy research paper service to make better their writing skills.   回復  更多評論   

            # re: gbk, gb2312,big5,unicode,utf-8,utf-16之間的關系 2010-07-24 08:28 buy essay papers

            Dream about well written academic papers? That's not hard! You just have to buy online essays at the experienced custom papers completing corporations for good prices.   回復  更多評論   

            # re: gbk, gb2312,big5,unicode,utf-8,utf-16之間的關系 2010-10-07 14:02 essay writers

            If settle to compose the non-plagiarized essay, you should get know that that demands a long period of time! Some students fail their custom term paper, just because they are not experienced enough! It is tragic, but the essay writing services will support such people any time they need.   回復  更多評論   

            # re: gbk, gb2312,big5,unicode,utf-8,utf-16之間的關系 2013-06-21 01:27 City of Doral

            City of Doral offers numerous quality services.   回復  更多評論   

            <2008年1月>
            303112345
            6789101112
            13141516171819
            20212223242526
            272829303112
            3456789

            導航

            統計

            常用鏈接

            留言簿(22)

            隨筆分類(30)

            隨筆檔案(29)

            文章分類

            搜索

            積分與排名

            最新評論

            閱讀排行榜

            評論排行榜

            国产精品综合久久第一页| 久久亚洲精品国产亚洲老地址| 五月丁香综合激情六月久久| 色偷偷88888欧美精品久久久| 精品久久久久久成人AV| 久久免费99精品国产自在现线| 国产精品乱码久久久久久软件| 国产成人精品久久一区二区三区| 久久五月精品中文字幕| 精品久久久无码人妻中文字幕豆芽 | 中文字幕久久欲求不满| 日韩影院久久| 亚洲国产天堂久久综合网站| 亚洲日韩欧美一区久久久久我| 国产精品对白刺激久久久| 久久精品国产精品亚洲| 欧美一区二区三区久久综合| 一本一本久久a久久精品综合麻豆| 久久久精品2019免费观看| 亚洲欧洲久久久精品| 精品久久久久久中文字幕| 亚洲精品乱码久久久久久久久久久久 | 久久久久人妻精品一区二区三区 | 久久96国产精品久久久| 亚洲а∨天堂久久精品9966| 久久综合欧美成人| 久久国产精品久久精品国产| 久久综合久久自在自线精品自| 中文成人无码精品久久久不卡| Xx性欧美肥妇精品久久久久久| 久久91精品国产91久久小草| MM131亚洲国产美女久久| 久久久久亚洲AV无码永不| 欧美喷潮久久久XXXXx| 日韩AV无码久久一区二区| 人妻精品久久久久中文字幕69 | 色青青草原桃花久久综合| 久久综合伊人77777麻豆| 亚洲人成无码www久久久| 久久综合久久美利坚合众国| 97久久国产综合精品女不卡|