這是一篇程序員寫給程序員的趣味讀物
所謂趣味是指可以比較輕松地了解一些原來不清楚的概念
增進知識
類似於打RPG游戲的升級
整理這篇文章的動機是兩個問題
問題一 使用Windows記事本的
另存為
可以在GBK
Unicode
Unicode big endian和UTF
這幾種編碼方式間相互轉換
同樣是txt文件
Windows是怎樣識別編碼方式的呢?
我很早前就發現Unicode
Unicode big endian和UTF
編碼的txt文件的開頭會多出幾個字節
分別是FF
FE(Unicode)
FE
FF(Unicode big endian)
EF
BB
BF(UTF
)
但這些標記是基於什麼標准呢?
問題二 最近在網上看到一個ConvertUTF
c
實現了UTF
UTF
和UTF
這三種編碼方式的相互轉換
對於Unicode(UCS
)
GBK
UTF
這些編碼方式
我原來就了解
但這個程序讓我有些糊塗
想不起來UTF
和UCS
有什麼關系
查了查相關資料
總算將這些問題弄清楚了
順帶也了解了一些Unicode的細節
寫成一篇文章
送給有過類似疑問的朋友
本文在寫作時盡量做到通俗易懂
但要求讀者知道什麼是字節
什麼是十六進制
big endian和little endian
big endian和little endian是CPU處理多字節數的不同方式
例如
漢
字的Unicode編碼是
C
那麼寫到文件裡時
究竟是將
C寫在前面
還是將
寫在前面?如果將
C寫在前面
就是big endian
如果將
寫在前面
就是little endian
endian
這個詞出自《格列佛游記》
小人國的內戰就源於吃雞蛋時是究竟從大頭(Big
Endian)敲開還是從小頭(Little
Endian)敲開
由此曾發生過六次叛亂
一個皇帝送了命
另一個丟了王位
我們一般將endian翻譯成
字節序
將big endian和little endian稱作
大尾
和
小尾
字符編碼內碼順帶介紹漢字編碼 字符必須編碼後才能被計算機處理
計算機使用的缺省編碼方式就是計算機的內碼
早期的計算機使用
位的ASCII編碼
為了處理漢字
程序員設計了用於簡體中文的GB
和用於繁體中文的big
GB
(
年)一共收錄了
個字符
包括
個漢字和
個其它符號
漢字區的內碼范圍高字節從B
F
低字節從A
FE
占用的碼位是
*
=
其中有
個空位是D
FA
D
FE
GB
支持的漢字太少
年的漢字擴展規范GBK
收錄了
個符號
它分為漢字區和圖形符號區
漢字區包括
個字符
從ASCII
GB
到GBK
這些編碼方法是向下兼容的
即同一個字符在這些方案中總是有相同的編碼
後面的標准支持更多的字符
在這些編碼中
英文和中文可以統一地處理
區分中文編碼的方法是高字節的最高位不為
按照程序員的稱呼
GB
GBK都屬於雙字節字符集 (DBCS)
年的GB
是取代GBK
的正式國家標准
該標准收錄了
個漢字
同時還收錄了藏文
蒙文
維吾爾文等主要的少數民族文字
從漢字字匯上說
GB
在GB
的
個漢字的基礎上增加了CJK擴展A的
個漢字(Unicode碼
x
x
db
)
一共收錄了
個漢字
CJK就是中日韓的意思
Unicode為了節省碼位
將中日韓三國語言中的文字統一編碼
GB
就是ISO/IEC
的中文版
相當於Unicode
GB
的編碼采用單字節
雙字節和
字節方案
其中單字節
雙字節和GBK是完全兼容的
字節編碼的碼位就是收錄了CJK擴展A的
個漢字
例如
UCS的
x
在GB
中的編碼應該是
EF
UCS的
x
在GB
中的編碼應該是
EF
微軟提供了GB
的升級包
但這個升級包只是提供了一套支持CJK擴展A的
個漢字的新字體
新宋體
並不改變內碼
Windows 的內碼仍然是GBK
這裡還有一些細節
GB
的原文還是區位碼
從區位碼到內碼
需要在高字節和低字節上分別加上A
對於任何字符編碼
編碼單元的順序是由編碼方案指定的
與endian無關
例如GBK的編碼單元是字節
用兩個字節表示一個漢字
這兩個字節的順序是固定的
不受CPU字節序的影響
UTF
的編碼單元是word(雙字節)
word之間的順序是編碼方案指定的
word內部的字節排列才會受到endian的影響
後面還會介紹UTF
GB
的兩個字節的最高位都是
但符合這個條件的碼位只有
*
=
個
所以GBK和GB
的低字節最高位都可能不是
不過這不影響DBCS字符流的解析
在讀取DBCS字符流時
只要遇到高位為
的字節
就可以將下兩個字節作為一個雙字節編碼
而不用管低字節的高位是什麼
UnicodeUCS和UTF 前面提到從ASCII
GB
GBK到GB
的編碼方法是向下兼容的
而Unicode只與ASCII兼容(更准確地說
是與ISO
兼容)
與GB碼不兼容
例如
漢
字的Unicode編碼是
C
而GB碼是BABA
Unicode也是一種字符編碼方法
不過它是由國際組織設計
可以容納全世界所有語言文字的編碼方案
Unicode的學名是
Universal Multiple
Octet Coded Character Set
簡稱為UCS
UCS可以看作是
Unicode Character Set
的縮寫
根據維基百科全書()的記載
歷史上存在兩個試圖獨立設計Unicode的組織
即國際標准化組織(ISO)和一個軟件制造商的協會()
ISO開發了ISO
項目
Unicode協會開發了Unicode項目
在
年前後
雙方都認識到世界不需要兩個不兼容的字符集
於是它們開始合並雙方的工作成果
並為創立一個單一編碼表而協同工作
從Unicode
開始
Unicode項目采用了與ISO
相同的字庫和字碼
目前兩個項目仍都存在
並獨立地公布各自的標准
Unicode協會現在的最新版本是
年的Unicode
ISO的最新標准是ISO
:
UCS只是規定如何編碼
並沒有規定如何傳輸
保存這個編碼
例如
漢
字的UCS編碼是
C
我可以用
個ascii數字來傳輸
保存這個編碼
也可以用utf
編碼:
個連續的字節E
B
來表示它
關鍵在於通信雙方都要認可
UTF
UTF
UTF
都是被廣泛接受的方案
UTF
的一個特別的好處是它與ISO
完全兼容
UTF是
UCS Transformation Format
的縮寫
IETF的RFC
和RFC
以RFC的一貫風格
清晰
明快又不失嚴謹地描述了UTF
和UTF
的編碼方法
我總是記不得IETF是Internet Engineering Task Force的縮寫
但IETF負責維護的RFC是Internet上一切規范的基礎
內碼和code page 目前Windows的內核已經支持Unicode字符集
這樣在內核上可以支持全世界所有的語言文字
但是由於現有的大量程序和文檔都采用了某種特定語言的編碼
例如GBK
Windows不可能不支持現有的編碼
而全部改用Unicode
Windows使用代碼頁(code page)來適應各個國家和地區
code page可以被理解為前面提到的內碼
GBK對應的code page是CP
微軟也為GB
定義了code page
CP
但是由於GB
有一部分
字節編碼
而Windows的代碼頁只支持單字節和雙字節編碼
所以這個code page是無法真正使用的
UCSUCSBMP UCS有兩種格式
UCS
和UCS
顧名思義
UCS
就是用兩個字節編碼
UCS
就是用
個字節(實際上只用了
位
最高位必須為
)編碼
下面讓我們做一些簡單的數學游戲
UCS
有
^
=
個碼位
UCS
有
^
=
個碼位
UCS
根據最高位為
的最高字節分成
^
=
個group
每個group再根據次高字節分為
個plane
每個plane根據第
個字節分為
行 (rows)
每行包含
個cells
當然同一行的cells只是最後一個字節不同
其余都相同
group
的plane
被稱作Basic Multilingual Plane
即BMP
或者說UCS
中
高兩個字節為
的碼位被稱作BMP
將UCS
的BMP去掉前面的兩個零字節就得到了UCS
在UCS
的兩個字節前加上兩個零字節
就得到了UCS
的BMP
而目前的UCS
規范中還沒有任何字符被分配在BMP之外
UTF編碼 UTF
就是以
位為單元對UCS進行編碼
從UCS
到UTF
的編碼方式如下
UCS
編碼(
進制) UTF
字節流(二進制)
F
xxxxxxx
FF
xxxxx
xxxxxx
FFFF
xxxx
xxxxxx
xxxxxx
例如
漢
字的Unicode編碼是
C
C
在
FFFF之間
所以肯定要用
字節模板了
xxxx
xxxxxx
xxxxxx
將
C
寫成二進制是
用這個比特流依次代替模板中的x
得到
即E
B
讀者可以用記事本測試一下我們的編碼是否正確
需要注意
UltraEdit在打開utf
編碼的文本文件時會自動轉換為UTF
可能產生混淆
你可以在設置中關掉這個選項
更好的工具是Hex Workshop
UTF
以
位為單元對UCS進行編碼
對於小於
x
的UCS碼
UTF
編碼就等於UCS碼對應的
位無符號整數
對於不小於
x
的UCS碼
定義了一個算法
不過由於實際使用的UCS
或者UCS
的BMP必然小於
x
所以就目前而言
可以認為UTF
和UCS
基本相同
但UCS
只是一個編碼方案
UTF
卻要用於實際的傳輸
所以就不得不考慮字節序的問題
UTF的字節序和BOM UTF
以字
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26766.html