1. 程式人生 > 其它 >常見編碼和編碼頭BOM

常見編碼和編碼頭BOM

中文編碼
  gb2312 (採用兩個位元組儲存字元漢字,英文數字一個位元組)
  GBK (採用兩個位元組儲存字元漢字,英文數字一個位元組)
  GB18030 (英文數字都是一個位元組,中文是兩個或四個位元組)
  Unicode字符集(包含每個國家的所有字元)國際通用
  unicode編碼 使用兩個位元組—65536個字元,浪費空間
為了節省空間使用轉碼形式
  utf-8 使用 1 、2、3個位元組 (EF BB BF 記事本新增的BOM(Byte Order Mark)頭,編碼的標記)
  utf-16 使用兩個位元組—65536個字元 (FF FE 小端(尾) FE FF 大端(尾))
  utf-32 使用4個位元組
  臺灣 big5
ANSI:在簡體中文Windows作業系統中, ANSI 編碼代表 GBK 編碼

BOM頭(記事本特有的)
BOM頭: Byte Order Mark
  標識檔案的編碼,實際大小比資料多3個位元組
  直接在記事本編輯資料儲存,預設會給你的資料新增上BOM頭,使你的檔案的大小比實際資料多3個位元組(utf-8編碼)。但是,當你使用java程式往記事本寫入資料的時候,不會新增BOM頭
  例如:當你用utf-8的格式編碼的時候,用程式去讀取檔案,雖然顯示的資料是檔案中儲存的資料,但是,可以用EditPlus開啟程式編譯後的.class檔案,並且轉化為16進位制展示,你就會發現,在前面的3個位元組會是 :EF BB BF 這三個位元組告訴記事本,這是一個用utf-8編碼的檔案。

  utf-8 EF BB BF
  utf-16(Unicode) FF FE 編碼的時候,小的在後面(FE在後面) 小端 little endian
  utf-16(Unicode big endian) FE FF 編碼的時候,大的在後面(FF在後面) 大端 little endian


ANSI
(American National Standards Institute,美國國家標準學會)
ANSI編碼標準是指所有從基本ASCII碼基礎上發展起來的編碼標準,
比如擴充套件的ASCII碼(128~255佔用)、GB2312、GBK、GB18030、BIG5等。每種編碼在ANSI標準中都為一頁,
比如encoding.gb2312頁代表GB2312字符集編碼

ASCII


(American Standard Code for Information Interchange,美國資訊交換標準碼)碼
ANSI的ASCII字符集佔一個位元組 ,8個位
起始佔用: 0x00-0x7f(127個字元狀態) ,半形
擴充後全部佔用: 0x00-0xff(共256個字元)

==========分界線====================================
GB2312
常說的全形,使用2個位元組編碼,共收錄了7445個字元,包括6763個漢字和682個其它符號
小於127的字元意義與原來相同,
當兩個大於127的位元組連在一起,就表示一個漢字,
前面的一個位元組(高位元組)從0xA1-0xF7,後面一個位元組(低位元組)從0xA1-0xFE。
GB2312的兩個位元組的最高位都是1,符合這個條件的碼位只有128*128=16384個

GBK
不再要求低位元組一定小於127,只要第一個位元組大於127,就認為是一個漢字的開始,
不管後面的位元組是否小於127,都要和第一個位元組組成一個兩位元組的漢字.
GBK包含了GB2312的所有內容,同時又增加了近20000個新的漢子(包括繁體字)和符號

BG18030
就是GBK的升級版,增加了很多字元,
中文Windows的預設內碼還是GBK,因為GB18030相對GBK增加的字元,

普通人是很難用到的

BG18030每個字可以由1個、2個或4個位元組組成
單位元組:其值從0到0x7F。
雙位元組:第一個位元組的值從0x81到0xFE,第二個位元組的值從0x40到0xFE(不包括0x7F)
四位元組:第一個位元組的值從0x81到0xFE,第二個位元組的值從0x30到0x39,第三個位元組從0x81到0xFE,第四個位元組從0x30到0x39。

BIG5
是香港、臺灣繁體中文區的字符集編碼標準。由於是各自獨立完成編碼標準,所以最後互相不相容。

從ASCII、GB2312、GBK到GB18030,,這些編碼方法是向前相容的,即同一個字元在這些方案
中總是有相同的編碼,區分中文編碼的方法是高位元組的最高位不為0。按照程式設計師的稱呼,
GB2312、GBK到GB18030和BIG5都屬於DBCS(double-byte charater set,雙位元組字符集)
或者說MBCS(mutil-byte charater set,多位元組字符集)
在DBCS雙位元組字符集中,GB內碼的儲存格式始終是big endian,即高位在前。
在讀取DBCS字元流時,只要遇到高位為1的位元組,就可以將下兩個位元組作為一個雙位元組編碼,
而不用管低位元組的高位是什麼。

==============分界線============================================
Unicode
Unicode的學名是"Universal Multiple-Octet Coded Character Set",簡稱為UCS。
UCS可以看作是"Unicode Character Set"的縮寫。
ISO(International Organization for Standardization或International Standard Organized)國際標準化組織
廢除了所有地區性編碼方案,重新搞了一套可以包含地球上所有文化的文字和符號的編碼方案。
他們稱這個方案為Universal Multiple-Octet Coded Character Set(通用多8位編碼字符集),簡稱UCS
ISO直接規定必須用兩個位元組,也就是16位來統一表示所有的字元,對於ASCII裡的那些“半形”字元,
UNICODE保持其原碼不變,只是將其由原來的8位擴充套件為16位,而其它文化和語言的字元則全部重新統一編碼。
由於“半形”英文符號只用到了低8位,所以其高8位永遠是0,會多浪費一倍的空間.
由於UNICODE設計初期的侷限性(並沒有考慮到與現有編碼的相容性),
所以使得UNICODE與GBK(GB18030、BG2312等)在排版上完全不一樣,
沒有一種簡單的演算法可以把內容從UNICODE編碼和兩一種編碼進行轉換,這種轉換必須通過查表來進行。
Unicode是2個位元組的編碼,所以也稱UCS-2,如果幾百年後地球上的字元又多了很多的話,ISO已經準備好了UCS-4方案了
也就是4個位元組的編碼,而Unicode只與ASCII相容(更準確地說,是與ISO-8859-1相容),與GB碼不相容。
例如“漢”字的Unicode編碼是6C49,而GB碼是BABA。

在非 Unicode 環境下,由於不同國家和地區採用的字符集不一致,很可能出現無法正常顯示所有字元的情況。
微軟公司使用了內碼表(Codepage)轉換表的技術來過渡性的部分解決這一問題,
即通過指定的轉換表將非 Unicode 的字元編碼轉換為同一字元對應的系統內部使用的 Unicode 編碼。
可以在“語言與區域設定”中選擇一個內碼表作為非Unicode編碼所採用的預設編碼方式,
如936為簡體中文GBK,950為正體中文Big5(皆指PC上使用的)。在這種情況下,
一些非英語的歐洲語言編寫的軟體和文件很可能出現亂碼。而將內碼表設定為相應語言中文處理又會出現問題,
這一情況無法避免。從根本上說,完全採用統一編碼才是解決之道,但目前尚無法做到這一點。
內碼表技術現在廣泛為各種平臺所採用。UTF-7(的內碼表是65000,UTF-8 的內碼表是65001。


UTF-8

任何文字在Unicode中都對應一個值,這個值稱為程式碼點code point.程式碼點的值通常寫成U+ABCD的格式
而文字和程式碼點之間的對應關係就是UCS-2(Universal Character Set coded in 2 octets)
UCS-4,即用四個位元組表示程式碼點。
它的範圍為 U+00000000~U+7FFFFFFF,其中 U+00000000~U+0000FFFF和UCS-2是一樣的。
UCS-2和UCS-4只規定了程式碼點和文字之間的對應關係,並沒有規定程式碼點在計算機中如何儲存。
規定儲存方式的稱為UTF(Unicode Transformation Format),其中應用較多的就是UTF-16和UTF-8了
UTF是“UCS Transformation Format”的縮寫,
是"Unicode字符集轉換格式",是"怎麼樣將Unicode定義的數字轉換成程式資料"
  UTF-8以位元組為單位對Unicode進行的特殊編碼。從Unicode到UTF-8的編碼方式如下:
  Unicode編碼(16進位制) ║ UTF-8 位元組流(二進位制)
  000000 - 00007F  ║ 0xxxxxxx
  000080 - 0007FF  ║ 110xxxxx 10xxxxxx
  000800 - 00FFFF  ║ 1110xxxx 10xxxxxx 10xxxxxx
  010000 - 10FFFF  ║ 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
UTF-8的特點是以位元組為單位對Unicode進行編碼,對不同範圍的字元使用不同長度的編碼。
對於0x00-0x7F之間的字元,UTF-8編碼與ASCII編碼完全相同。UTF-8編碼的最大長度是4個位元組。
從上表可以看出,4位元組模板有21個x,即可以容納21位二進位制數字。Unicode的最大碼位0x10FFFF也只有21位。
例1:“漢”字的Unicode編碼是0x6C49。0x6C49在0x0800-0xFFFF之間,使用3位元組模板了 1110xxxx 10xxxxxx 10xxxxxx
將0x6C49寫成二進位制是:0110 1100 0100 1001, 用這個位元流依次代替模板中的x,
得到:11100110 10110001 10001001,即E6 B1 89。
例2:Unicode編碼0x20C30在0x010000-0x10FFFF之間,使用用4位元組模板了:
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx。
將0x20C30寫成21位二進位制數字(不足21位就在前面補0):0 0010 0000 1100 0011 0000,
用這個位元流依次代替模板中的x,
得到:11110000 10100000 10110000 10110000,即F0 A0 B0 B0。
UTF-8是ASCII的一個超集。因為一個純ASCII字串也是一個合法的UTF-8字串,所以現存的ASCII文字不需要轉換。
為傳統的擴充套件ASCII字符集設計的軟體通常可以不經修改或很少修改就能與UTF-8一起使用。
使用標準的面向位元組的排序例程對UTF-8排序將產生與基於Unicode程式碼點排序相同的結果。
(儘管這隻有有限的有用性,因為在任何特定語言或文化下都不太可能有仍可接受的文字排列順序。)
UTF-8和UTF-16都是可擴充套件標記語言文件的標準編碼。所有其它編碼都必須通過顯式或文字宣告來指定。
任何面向位元組的字串搜尋演算法都可以用於UTF-8的資料(只要輸入僅由完整的UTF-8字元組成)。
但是,對於包含字元記數的正則表示式或其它結構必須小心。


UTF-16
UTF-16編碼以16位無符號整數為單位,詳見百度google

UTF-32
UTF-32編碼以32位無符號整數為單位,詳見百度google

===========分界線============================================
位元組序
PowerPC系列採用big endian方式儲存資料,
而x86系列則採用little endian方式儲存資料,
比如:0x12345678 雙字型資料 ,佔4個位元組
低位資料----------------->高位資料
12 34 56 78 H

低地址------------------->高地址
0x01 0x02 0x03 0x04 記憶體中
| 12 | 34 | 56 | 78 | big endian 方式
| 78 | 56 | 34 | 12| little endian方式
little endian方式個人理解:
(起始地址存放高位資料,左邊12是低資料位放在尾部,是低資料位,不是指二進位制中的右邊的低數值位)

C/C++語言編寫的程式裡資料儲存順序是跟編譯平臺所在的CPU相關的,
而java是跨平臺的,採用big endian方式來儲存資料
網路位元組序也是big endian方式


BOM
BOM(byte-order mark)檔案編碼頭,即 位元組順序標記.
它是插入到以UTF-8、UTF16或UTF-32編碼檔案開頭的特殊標記,
用來標記多位元組編碼檔案的編碼型別和位元組順序(big-endian或little- endian)。
一般用來識別檔案的編碼型別。

根據位元組序的不同,UTF-16可以被實現為UTF-16LE或UTF-16BE,UTF-32可以被實現為UTF-32LE或UTF-32BE。
例如:
  Unicode編碼  ║ UTF-16LE  ║ UTF-16BE  ║ UTF32-LE  ║ UTF32-BE
  0x006C49  ║ 49 6C  ║ 6C 49  ║ 49 6C 00 00 ║ 00 00 6C 49
  0x020C30  ║ 43 D8 30 DC║ D8 43 DC 30 ║ 30 0C 02 00 ║ 00 02 0C 30
Unicode標準建議用BOM(ByteOrderMark)來區分位元組序,
即在傳輸位元組流前,先傳輸被作為BOM的字元"零寬無中斷空格"。
這個字元的編碼是FEFF,而反過來的FFFE(UTF-16)和FFFE0000(UTF-32)在Unicode中都是未定義的碼位,
不應該出現在實際傳輸中。

BOM編碼頭 常見形式如下:
EF BB BF = UTF-8 (可選標記,因為Unicode標準未有建議)

FE FF = UTF-16, big-endian (大尾位元組序標記)
FF FE = UTF-16, little-endian (小尾位元組序標記) (也是windows中的Unicode編碼預設標記)

00 00 FE FF = UTF-32, big-endian (大尾位元組序標記)
FF FE 00 00 = UTF-32, little-endian (小尾位元組序標記)

對於UTF-8來說,BOM標記的有無並不是必須的,是可選的,因為UTF8位元組沒有順序,不需要標記.
也就是說一個UTF-8檔案可能有BOM,也可能沒有BOM.

微軟在自己的UTF-8格式的文字檔案之前加上了EF BB BF三個位元組,
windows上面的notepad等程式就是根據這三個位元組來確定一個文字檔案是ASCII的還是UTF-8的,
然而這個只是微軟暗自作的標記, 其它平臺上不一定會對UTF-8文字檔案做個這樣的標記。
微軟的一些軟體會做這種檢測,但有些軟體不做這種檢測, 而把它當作正常字元處理。(傳說中的亂碼問題)


再舉個例子
說的是Notepad2這個體積小,啟動速度快,功能強的輕量級文字編輯器,程式碼高亮等,完全可以替代系統記事本
以前剛用Notepad2的時候,經常在開啟一個文字檔案時顯示亂碼,點什麼編碼轉換也沒用,
比如ViDown.exe維棠下載器程式目錄下的Readme.txt,開啟就是亂碼,點選"檔案","編碼"方式,看到的是Unicode,
ok.先關掉Readme.txt,用16進位制編輯器比如Hex WorkShop開啟後發現前2個位元組是CF C2,這在GBK中的編碼是
下載的"下",說明該Readme.txt編碼不是Unicode,而是屬於ANSI編碼,
那麼避免亂碼就要對Notepad2設定下,點"檔案","編碼',"預設",在下拉選單中找到ANSI936,(上面說過它就是GBK)
並勾上"跳過Unicode檢測", 好了再開啟Readme.txt就正常顯示中文了.
在"檔案","編碼',下有"UTF-8"和"UTF-8包含簽名",這2個有什麼區別呢?
其中"UTF-8包含簽名",這一選項是將檔案編碼格式轉換為UTF-8(包含BOM編碼頭),
翻譯成"包含簽名"就看不懂了...

我用Notepad2新建個文字,寫上2個字: 我a
1.先轉成ANSI編碼:用Hex WorkShop開啟 CE D2 61 (我:CE D2 , a:61H)
2.轉成Unicode編碼:(little-endian) FF FE 11 62 61 00 (我:6211H , a:0061H)
3.轉成Unicode編碼:(big-endian) FE FF 62 11 00 61
4.轉成UTF-8編碼: E6 88 91 61 (我:E68891H , a:61H)
5.轉成UTF-8編碼:(帶BOM) EF BB BF E6 88 91 61(就多了個EF BB BF頭)