常見字符編碼介紹以及相互轉換

最近在用JS時,涉及到了不同編碼之間的轉換.於是彙總了一些網上的資料,整合成了自己的文檔. 

-備忘錄

知識點涉及: 字符編碼基礎,不同編碼之間的轉換,如UTF-8轉UTF-16,如UTF-16轉GBK;以及Base64加密,GBK型與UTF-8型加密等.

注:

參考來源於網上資料

來源1: http://my.oschina.net/goal/blog/201032?fromerr=vEgm5b1A#OSC_h2_1

來源2: http://www.qqxiuzi.cn/zh/hanzi-gb2312-bianma.php

來源3: http://www.qqxiuzi.cn/zh/hanzi-gbk-bianma.php

來源4: http://www.qqxiuzi.cn/zh/hanzi-gb2312-bianma.php

來源5: http://www.qqxiuzi.cn/zh/hanzi-BIG5-bianma.php

來源6: http://www.fmddlmyy.cn/text6.html

來源7: http://www.cnblogs.com/hongru/archive/2012/01/14/2321397.html

來源8: http://www.jb51.net/article/62415.htm

幾種常用編碼

ASCII碼

1.1.1.1、       簡介

(American Standand Code for InformationInterchange)的縮寫

ASCII碼是計算機最開始支持的基於拉丁字母的編碼,一個字符用一個字節表示,只用了低7位,最高位爲0,因此總共有128個ASCII碼,範圍爲0~127。

1.1.1.2、       編碼範圍

0~127(總共有128個ASCII碼),詳情百度ASCII碼錶

1.1.1.3、       適用範圍以及存在問題

適用於現代英文和其它西歐語言.

但是由於編碼範圍有限,所以無法支持多種地區的語言,後來就產生了各種其它的編碼

方案

1.1.1.4、       特性

1.1.1.4.1、          單字節編碼

只佔用一個字節

高位不佔用,最多爲(01111111)


ISO-8859-1編碼

1.1.1.1、       簡介

即”標準碼”,通常叫做Latin-1

ISO-8859-1編碼是單字節編碼,向下兼容ASCII,其編碼範圍是0x00-0xFF,0x00-0x7F之間完全和ASCII一致,0x80-0x9F之間是控制字符,0xA0-0xFF之間是文字符號

1.1.1.2、       編碼範圍

0x00-0xFF(0-255)

1.1.1.3、       適用範圍以及存在問題

此字符集支持部分於歐洲使用的語言,包括阿爾巴尼亞語、巴斯克語、布列塔尼語、加泰羅尼亞語、丹麥語、荷蘭語、法羅語、弗裏西語、加利西亞語、德語、格陵蘭語、冰島語、愛爾蘭蓋爾語、意大利語、拉丁語、盧森堡語、挪威語、葡萄牙語、裏託羅曼斯語、蘇格蘭蓋爾語、西班牙語及瑞典語。

但是不支持中文和東亞等國的語言.

1.1.1.3.1、          單字節編碼

只佔用一個字節

高位可以用,最多爲(11111111)


GB2312編碼

1.1.1.1、       簡介

GB是”國標”兩字的拼音首字,2312是標準序號

GB2312編碼是第一個漢字編碼國家標準,由中國國家標準總局1980年發佈,1981年5月1日開始使用。GB2312編碼共收錄漢字6763個,其中一級漢字3755個,二級漢字3008個。同時,GB2312編碼收錄了包括拉丁字母、希臘字母、日文平假名及片假名字母、俄語西裏爾字母在內的682個全角字符。

(GB2312中的字符是全角字符,ASCII原始的字符是半角字符)

1.1.1.2、       編碼範圍

A1A1-FEFE(41377-65278)

其中漢字編碼範圍:B0A1-F7FE(45217-63486)。

1.1.1.3、       適用範圍以及存在問題

基本滿足了漢字的計算機處理需要,它所收錄的漢字已經覆蓋中國大陸99.75%的使用頻率。但對於人名、古漢語等方面出現的罕用字和繁體字,GB 2312不能處理,因此後來GBK及GB 18030漢字字符集相繼出現以解決這些問題

中國大陸幾乎所有的中文系統和國際化的軟件都支持GB 2312

1.1.1.4、       特性

1.1.1.4.1、          分區表示

GB2312編碼對所收錄字符進行了“分區”處理,共94個區,每區含有94個位,共8836個碼位。這種表示方式也稱爲區位碼。

01-09區收錄除漢字外的682個字符。

10-15區爲空白區,沒有使用。

16-55區收錄3755個一級漢字,按拼音排序。

56-87區收錄3008個二級漢字,按部首/筆畫排序。

88-94區爲空白區,沒有使用。

舉例來說,“啊”字是GB2312編碼中的第一個漢字,它位於16區的01位,所以它的區位碼就是1601

1.1.1.4.2、          雙字節編碼

GB2312規定對收錄的每個字符采用兩個字節表示,第一個字節爲“高字節”,對應94個區;第二個字節爲“低字節”,對應94個位。所以它的區位碼範圍是:0101-9494。區號和位號分別加上0xA0就是GB2312編碼。例如最後一個碼位是9494,區號和位號分別轉換成十六進制是5E5E,0x5E+0xA0=0xFE,所以該碼位的GB2312編碼是FEFE。

GB2312編碼範圍:A1A1-FEFE,其中漢字的編碼範圍爲B0A1-F7FE,第一字節0xB0-0xF7(對應區號:16-87),第二個字節0xA1-0xFE(對應位號:01-94)

注: 屬於原標準碼的部分仍然採取單字節編碼

GBK編碼

1.1.1.1、       簡介

即漢字國標擴展碼,

GBK編碼,是對GB2312編碼的擴展,因此完全兼容GB2312-80標準。GBK編碼依然採用雙字節編碼方案,其編碼範圍:8140-FEFE,剔除xx7F碼位,共23940個碼位。共收錄漢字和圖形符號21886個,其中漢字(包括部首和構件)21003個,圖形符號883個。GBK編碼支持國際標準ISO/IEC10646-1和國家標準GB13000-1中的全部中日韓漢字,幷包含了BIG5編碼中的所有漢字。GBK編碼方案於1995年12月15日正式發佈,這一版的GBK規範爲1.0版。

Windows 95系統就是以GBK爲內碼,又由於GBK同時也涵蓋了Unicode所有CJK漢字,所以也可以和Unicode做一一對應

1.1.1.2、       編碼範圍

8140-FEFE (33088-65278)

全部編碼分爲三大部分:1.漢字區;2.圖形符號區;3.用戶自定義區(詳情見特性碼位分配及順序)

1.1.1.3、       適用範圍以及存在問題

幾乎完美支持漢字,但是不支持部分國家的語言(如一些東亞國家,日本等)

所以經常會有GBK到UNICODE的轉換

1.1.1.4、       特性

1.1.1.4.1、          字彙

GBK 規範收錄了 ISO 10646.1 中的全部 CJK 漢字和符號,並有所補充。具體包括:

1. GB 2312 中的全部漢字、非漢字符號。

2. GB 13000.1 中的其他 CJK 漢字。以上合計 20902 個 GB 化漢字。

3. 《簡化字總表》中未收入 GB 13000.1 的 52 個漢字。

4. 《康熙字典》及《辭海》中未收入 GB 13000.1 的 28 個部首及重要構件。

5. 13 個漢字結構符。

6. BIG-5 中未被 GB 2312 收入、但存在於 GB 13000.1 中的 139 個圖形符號。

7. GB 12345 增補的 6 個拼音符號。

8. 漢字“○”。

9. GB 12345 增補的 19 個豎排標點符號(GB12345 較 GB 2312 增補豎排標點符號 29 個,其中 10 個未被 GB 13000.1 收入,故 GBK 亦不收)。

10. 從 GB 13000.1 的 CJK 兼容區挑選出的 21 個漢字。

11. GB 13000.1 收入的 31 個 IBM OS/2 專用符號。

12.未錄入《新華字典》上的一些字,如“韡”的簡體。

1.1.1.4.2、          碼位分配及順序

GBK 亦採用雙字節表示,總體編碼範圍爲 8140-FEFE,首字節在 81-FE 之間,尾字節在 40-FE 之間,剔除 xx7F 一條線。總計 23940 個碼位,共收入 21886 個漢字和圖形符號,其中漢字(包括部首和構件)21003 個,圖形符號 883 個。

 

全部編碼分爲三大部分:

 

1. 漢字區。包括:

a. GB 2312 漢字區。即 GBK/2: B0A1-F7FE。收錄 GB 2312 漢字 6763 個,按原順序排列。

b. GB 13000.1 擴充漢字區。包括:

(1) GBK/3: 8140-A0FE。收錄 GB 13000.1 中的 CJK 漢字 6080 個。

(2) GBK/4: AA40-FEA0。收錄 CJK 漢字和增補的漢字 8160 個。CJK 漢字在前,按 UCS 代碼大小排列;增補的漢字(包括部首和構件)在後,按《康熙字典》的頁碼/字位排列。

 

2. 圖形符號區。包括:

a. GB 2312 非漢字符號區。即 GBK/1: A1A1-A9FE。其中除 GB 2312 的符號外,還有 10 個小寫羅馬數字和 GB12345 增補的符號。計符號 717 個。

b. GB 13000.1 擴充非漢字區。即 GBK/5: A840-A9A0。BIG-5 非漢字符號、結構符和“○”排列在此區。計符號 166 個。

 

3. 用戶自定義區:分爲(1)(2)(3)三個小區。

(1) AAA1-AFFE,碼位 564 個。

(2) F8A1-FEFE,碼位 658 個。

(3) A140-A7A0,碼位 672 個。

第(3)區儘管對用戶開放,但限制使用,因爲不排除未來在此區域增補新字符的可能性

1.1.1.4.3、          字形

GBK 對字形作了如下的規定:

1. 原則上與 GB 13000.1 G列(即源自中國大陸法定標準的漢字)下的字形/筆形保持一致。

2. 在 CJK 漢字認同規則的總框架內,對所有的 GBK 編碼漢字實施“無重碼正形”(“GB 化”);即在不造成重碼的前提下,儘量採用中國新字形。

3. 對於超出 CJK 漢字認同規則的、或認同規則尚未明確規定的漢字,在 GBK 碼位上暫安放舊字形。這樣,在許多情況下 GBK 收入了同一漢字的新舊兩種字形。

4. 非漢字符號的字形,凡 GB 2312 已經包括的,與 GB 2312 保持一致;超出 GB 2312 的部分,與 GB 13000.1 保持一致。

5. 帶聲調的拼音字母取半角形式。

 

1.1.1.4.3.1、       誤處理

低字節是0x40-0x7E的GBK字符有一定特殊性,因爲這些字符佔用了ASCII碼的位置,這樣會給一些系統帶來麻煩。

有些系統中用0x40-0x7E中的字符(如“|”)做特殊符號,在定位這些符號時又沒有判斷這些符號是不是屬於某個 GBK字符的低字節,這樣就會造成錯誤判斷。在支持GB2312的環境下就不存在這個問題。需要注意的是支持GBK的環境中小於0x80的某個字節未必就 是ASCII符號;另外就是最好選用小於0×40的ASCII符號做一些特殊符號,這樣就可以快速定位,且不用擔心是某個漢字的另一半。Big5編碼中也存在相應問題。

1.1.1.4.4、          雙字節編碼

遵循GB2312規定

GB18030編碼


1.1.1.1、       簡介

2000年3月17日發佈的漢字編碼國家標準GB18030編碼,是對GBK編碼的擴充,覆蓋中文、日文、朝鮮語和中國少數民族文字,其中收錄27484個漢字。GB18030字符集採用單字節、雙字節和四字節三種方式對字符編碼。兼容GBK和GB2312字符集。

 

國家標準GB18030-2005《信息技術 中文編碼字符集》是我國繼GB2312-1980和GB13000-1993之後最重要的漢字編碼標準,是我國計算機系統必須遵循的基礎性標準之一。 GB18030有兩個版本:GB18030-2000和GB18030-2005。GB18030-2000是GBK的取代版本,它的主要特點是在GBK基礎上增加了CJK統一漢字擴充A的漢字。GB18030-2005的主要特點是在GB18030-2000基礎上增加了CJK統一漢字擴充B的漢字。

 

GB18030-2000編碼標準《信息技術漢字編碼字符集 基本集的擴充》是由信息產業部和國家質量技術監督局在2000年3月17日聯合發佈的,並且將作爲一項國家標準在2001年的1月正式強制執行。GB18030-2000僅規定了常用非漢字符號和27533個漢字(包括部首、部件等)的編碼。

 

GB18030-2005《信息技術中文編碼字符集》是以漢字爲主幷包含多種我國少數民族文字的超大型中文編碼字符集,其中收入漢字70000餘個。在GB18030-2000的基礎上增加了42711個漢字和多種我國少數民族文字的編碼(如藏、蒙古、傣、彝、朝鮮、維吾爾文等)。增加的這些內容是推薦性的,原GB18030-2000中的內容是強制性的,市場上銷售的產品必須符合。故GB18030-2005爲部分強制性標準,自發布之日起代替GB18030-2000。

1.1.1.2、       編碼範圍

採用單字節、雙字節、四字節分段編碼方案,具體碼位見特性。

GB18030向下兼容GBK和GB2312編碼。

1.1.1.3、       適用範圍以及存在問題

GB18030可用於一切處理中文(包括漢字和少數民族文)信息,特別是漢字信息的信息處理產品。

1.1.1.4、       特性

1.1.1.4.1、          GB18030-2000字彙

GB18030-2000標準收錄的字符分別以單字節、雙字節和四字節編碼。

1、單字節部分

本標準中,單字節的部分收錄了GB11383的0x00到0x7F全部128個字符及單字節編碼的歐元符號。

2、雙字節部分

本標準中,雙字節的部分收錄內容如下:

GB 13000.1的全部CJK統一漢字字符。

GB 13000.1的CJK兼容區挑選出來的21個漢字。

GB 13000.1中收錄而GB 2312未收錄的我國臺灣地區使用的圖形字符139個。

GB 13000.1收錄的其它字符31個。

GB 2312中的非漢字符號。

GB 12345 的豎排標點符號19個。

GB 2312未收錄的10個小寫羅馬數字。

GB 2312未收錄的帶音調的漢語拼音字母5個以及ɑ 和ɡ。

漢字數字“〇”。

表意文字描述符13個。

增補漢字和部首/構件80個。

雙字節編碼的歐元符號。

3 、四字節部分

本標準的四字節的部分,收錄了上述雙字節字符之外的,包括CJK統一漢字擴充A在內的GB 13000.1 中的全部字符。

1.1.1.4.2、          GB18030-2005字彙

GB18030-2005標準收錄的字符分別以單字節、雙字節或四字節編碼。

 

1、單字節部分

本標準中,單字節的部分收錄了GB/T11383-1989的0x00到0x7F全部128個字符。

 

2、雙字節部分

本標準中,雙字節的部分收錄內容如下:

GB 13000.1-1993的全部CJK統一漢字字符。

GB 13000.1-1993的CJK兼容區挑選出來的21個漢字。

GB 13000.1-1993中收錄而GB 2312未收錄的我國臺灣地區使用的圖形字符139個。

GB 13000.1-1993收錄的其它字符31個。

GB 2312中的非漢字符號。

GB 12345 的豎排標點符號19個。

GB 2312未收錄的10個小寫羅馬數字。

GB 2312未收錄的帶音調的漢語拼音字母5個以及ɑ 和ɡ。

漢字數字“〇”。

表意文字描述符13個。

對GB 13000.1-1993增補的漢字和部首/構件80個。

雙字節編碼的歐元符號。

 

3、四字節部分

本標準的四字節的部分,收錄了上述雙字節字符之外的,GB 13000的CJK統一漢字擴充A、CJK統一漢字擴充B和已經在GB13000中編碼的我國少數民族文字的字符。

GB18030-2005最主要的變化是增加了CJK統一漢字擴充B。它還去掉了單字節編碼的歐元符號0x80)。

GB18030有1611668個碼位,在GB18030-2005中定義了76556個字符。隨着我國漢字整理和編碼研究工作的不斷深入,以及國際標準ISO/IEC 10646的不斷髮展,GB18030所收錄的字符將在新版本中增加。

1.1.1.4.3、          GB18030-2000漢字

如下表所示,GB18030-2000收錄了27533個漢字:

 

類別

碼位範圍

碼位數

字符數

字符類型

雙字節部分

第一字節0xB0-0xF7

6768

6763

漢字

第二字節0xA1-0xFE

第一字節0x81-0xA0

6080

6080

漢字

第二字節0x40-0xFE

第一字節0xAA-0xFE

8160

8160

漢字

第二字節0x40-0xA0

四字節部分

第一字節0x81-0x82

6530

6530

CJK統一漢字擴充A

第二字節0x30-0x39

第三字節0x81-0xFE

第四字節0x30-0x39

27533就是6763+6080+8160+6530。雙字節部分的6763+6080+8160=21003個漢字就是GBK的21003個漢字。

在Unicode中,CJK統一漢字擴充A有6582個漢字,爲什麼這裏只有6530個漢字?

這是因爲在GBK時代,雙字節部分已經收錄過CJK統一漢字擴充A的52個漢字,所以還餘6530個漢字。

1.1.1.4.4、          GB18030-2005漢字

如下表所示,GB18030-2005收錄了70244個漢字:

 

類別

碼位範圍

碼位數

字符數

字符類型

雙字節部分

第一字節0xB0-0xF7

6768

6763

漢字

第二字節0xA1-0xFE

第一字節0x81-0xA0

6080

6080

漢字

第二字節0x40-0xFE

第一字節0xAA-0xFE

8160

8160

漢字

第二字節0x40-0xA0

四字節部分

第一字節0x81-0x82

6530

6530

CJK統一漢字擴充A

第二字節0x30-0x39

第三字節0x81-0xFE

第四字節0x30-0x39

第一字節0x95-0x98

42711

42711

CJK統一漢字擴充B

第二字節0x30-0x39

第三字節0x81-0xFE

第四字節0x30-0x39

70244就是6763+6080+8160+6530+42711。

BIG5 編碼

1.1.1.1、       簡介

BIG5編碼又稱大五碼,是繁體中文字符集編碼標準,共收錄13060箇中文字,其中有二字爲重複編碼。

BIG5採用雙字節編碼,使用兩個字節來表示一個字符。高位字節使用了0x81-0xFE,低位字節使用了0x40-0x7E,及0xA1-0xFE。在BIG5的分區中:

8140-A0FE 保留給使用者自定義字符(造字區)

A140-A3BF 標點符號、希臘字母及特殊符號。其中在A259-A261,收錄了度量衡單位用字:兙兛兞兝兡兣嗧瓩糎。

A3C0-A3FE 保留。此區沒有開放作造字區用。

A440-C67E 常用漢字,先按筆劃再按部首排序。

C6A1-F9DC 其它漢字。

F9DD-F9FE 製表符。

值得留意的是,BIG5重複地收錄了兩個相同的字:“兀、兀”(A461及C94A)、“嗀、嗀”(DCD1及DDFC)。

1.1.1.2、       編碼範圍

8140-FEFE(33088-65278)

其中漢字編碼範圍:A440-F9DC(42048-63964)

1.1.1.3、       適用範圍以及存在問題

適用於臺灣和香港地區的繁體中文系統軟件等.不過由於編碼本身存在的問題.已經基本改用Unicode編碼了.

1.1.1.3.1.1、       兼容問題:

由於各廠商及政府推出的Big5延伸,彼此互不兼容,造成亂碼問題。

1.1.1.3.1.2、       衝碼問題

因爲低位元字符中包含了編程語言、shell、script 中,字串或命令常會用到的特殊字符,例如0x5C “\”、0x7C “|”等。“\”在許多用途的字串中是當作轉義符號又稱爲跳脫字符,例如 \n(換行)、\r(歸位)、\t(tab)、\\(\本身符號)、\"(引號)等等。而 “|” 在UNIX操作系統中大多當作命令管線的使用,如 "ls -la | more" 等等。如果在字串中有這些特殊的轉義字符,會

BIG-5

BIG-5

被程式或直譯器解釋爲特殊用途。但是因爲是中文的原因,故無法正確解釋爲上面所述的行爲,因此程式可能會忽略此轉義符號或是中斷執行。若此,就違反了使用者本來要當成中文字符一部份使用的本意。

在常用字如“功”(0xA55C)、“許”(0xB35C)、“蓋”(0xBB5C)、“育”(0xA87C)中時常出現,造成了許多軟件無法正確處理以Big5編碼的字串或文件。這個問題被戲謔性地人名化,稱爲“許功蓋”或“許蓋功”(這三個字都有這種問題)。但是額外的困擾是,有些輸出功能並不會把“\”當作特殊字符看待,所以有些程式或網頁就會錯誤地常常出現在“許功蓋”這些字後面多了“\”。

1.1.1.3.1.3、       私人造字

在倚天中文系統,以及後來的Windows3.1、95及98中,定義了四個私人造字區範圍:0xFA40-0xFEFE、0x8E40-0xA0FE、0x8140-0x8DFE、0xC6A1-0xC8FE。私人造字區的原意,是供使用者加入本來在編碼表中缺少的字符,但當每個使用者都在不同的地方加上不同的字符後,當交換資料時,對方便難以知道某一個編碼究竟想表達什麼字

1.1.1.4、       特性

1.1.1.4.1.1、       雙字節編碼

Big5是雙字節編碼,高字節編碼範圍是0x81-0xFE,低字節編碼範圍是0x40-0x7E和0xA1-0xFE。和GBK相比,少了低字節是0x80-0xA0的組合。0x8140-0xA0FE是保留區域,用於用戶造字區

1.1.1.4.1.2、       字符有限

Big5收錄的漢字只包括繁體漢字,不包括簡體漢字,一些生僻的漢字也沒有收錄。GBK收錄的日文假名字符、俄文字符Big5也沒有收錄。因爲Big5當中收錄的字符有限,因此有很多在Big5基礎上擴展的編碼,如倚天中文系統。Windows系統上使用的代碼頁CP950也可以理解爲是對Big5的擴展,在Big5的基礎上增加了7個漢字和一些符號。Big5編碼對應的字符集是GBK字符集的子集,也就是說Big5收錄的字符是GBK收錄字符的一部分,但相同字符的編碼不同。

會有

1.1.1.4.1.3、       誤處理

因爲Big5也佔用了ASCII的編碼空間(低字節所使用的0x40-0x7E),所以Big5編碼在一些環境下存在和GBK編碼相同的問題,即低字節範圍爲0x40-0x7E的字符有可能會被誤處理,尤其是低字節是0x5C("/")和0x7C("|")的字符。可以參考GBK一節相應說明。

Unicode 編碼

1.1.1.1、       簡介

Unicode 是全球文字統一編碼。它把世界上的各種文字的每一個字符指定唯一編碼,實現跨語種、跨平臺的應用。

Unicode(統一碼、萬國碼、單一碼)是計算機科學領域裏的一項業界標準,包括字符集、編碼方案等。Unicode是爲了解決傳統的字符編碼方案的侷限而產生的,它爲每種語言中的每個字符設定了統一併且唯一的二進制編碼,以滿足跨語言、跨平臺進行文本轉換、處理的要求。1990年開始研發,1994年正式公佈。

1.1.1.1.1.1、       Tips

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年的Unicode4.1.0。ISO的最新標準是ISO 10646-3:2003。

 

UCS只是規定如何編碼,並沒有規定如何傳輸、保存這個編碼。例如“漢”字的UCS編碼是6C49,我可以用4個ascii數字來傳輸、保存這個編碼;也可以用utf-8編碼:3個連續的字節E6 B1 89來表示它。關鍵在於通信雙方都要認可。UTF-8、UTF-7、UTF-16都是被廣泛接受的方案。UTF-8的一個特別的好處是它與ISO-8859-1完全兼容。UTF是“UCS Transformation Format”的縮寫。

 

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

1.1.1.2、       編碼範圍

詳情百度Unicode編碼範圍.

例如,中文範圍爲: 4E00-9FBF,其中

CJK 統一表意符號(4DC0-4DFF)等等…

Unicode是一種規範,具體的實現由各自實現的編碼方式決定.

1.1.1.3、       適用範圍

作爲一種全球統一編碼,適用於世界範圍,有多種實現方式.

(如utf-8,utf-16,utf-32)

1.1.1.4、       特性

Unicode只是一種規範,沒有明確規定實現方式.所有不同的實現方案有着不同的存儲方式等

(如utf-8,utf-16,utf-32的區別)

1.1.2、           UTF-8編碼

1.1.2.1、       簡介

UTF-8是Unicode的一種實現方式,根據不同的Unicode字符,用1到6個字節編碼.

UTF-8的字節結構有特殊要求,比如我們說一個漢字的範圍是0X4E00到0x9FA5,是指unicode值,至於放在utf-8的編碼裏去就是由三個字節來組織.

注:遵循Unicode規範.

1.1.2.2、       特性

1.1.2.2.1、          變長編碼

根據不同的Unicode字符,用1到6個字節編碼

1.1.2.3、       實現方式

1.1.2.3.1、          Unicode和Utf-8對照表

UTF8是採用變長的編碼方式,爲1~6個字節,但通常我們只把它看作單字節或三字節的實現,因爲其它情況實在少見。UTF8編碼通過多個字節組合的方式來顯示,這是計算機處理UTF8的機制,它是無字節序之分的,並且每個字節都非常有規律,詳見上圖

UTF-16 編碼

1.1.1.1、       簡介

UTF-16是Unicode的一種實現方式.

UTF-16是完全對應於UCS-2的,即把UCS-2規定的代碼點通過Big Endian或Little Endian方式直接保存下來。所以UTF-16採用2個字節來存儲Unicode。UTF-16也可以表示UCS-4的部分字符,所以UTF-16也採用4個字節來存儲Unicode。

UTF16編碼是Unicode最直接的實現方式,通常我們在windows上新建文本文件後保存爲Unicode編碼,其實就是保存爲UTF16編碼。

1.1.1.1.1、          Tips

1.      Javascript內置的實現就是UTF-16編碼

2.      UTF-16比起UTF-8,好處在於大部分字符都以固定長度的字節 (2字節) 儲存,但UTF-16卻無法兼容於ASCII編碼。

3.      大端字節序,高字節存於內存低地址,低字節存於內存高地址;小端字節序反之

如一個long型數據0x12345678

大端字節序:

內存低地址--> 0x12

             0x34

       0x56

內存高地址--> 0x78

 

小端字節序:

內存低地址--> 0x78     

       0x56

       0x34

內存高地址--> 0x12

1.1.1.2、       特性

1.1.1.2.1、          不兼容ASCII碼

由於UTF-16固定是兩字節的(UCS-4部分字符4字節),所以無法支持單字節的ASCII碼

1.1.1.2.2、          實現方式

因爲是多字節存儲,所以它的存儲方式分爲2種:大端序和小端序。

UTF16編碼在windows上採用小端序的方式存儲;而比如JavaScript語言,它內部就是採用UTF16編碼,並且它的存儲方式爲大端序。

UTF-32 編碼

1.1.1.1、       簡介

UTF-32是Unicode的一種實現方式.

UTF32編碼使用固定的4個字節來存儲。

因此,非常浪費空間,不利於網絡傳輸,所以使用不普遍。

Tips: Html5中明確規定禁止使用Utf-32編碼.

1.1.1.2、       特性

浪費空間,使用不普遍


ANSI 編碼

1.1.1.1、       簡介

(American National Standards Institute) 美國國家標準學會的縮寫

針對漢字的編碼,不同的國家和地區制定了不同的標準,由此產生了 GB2312、GBK、Big5、Shift_JIS 等各自的編碼標準。這些使用 1 至 4 個字節來代表一個字符的各種漢字延伸編碼方式,稱爲ANSI 編碼。

例如:在簡體中文Windows操作系統中,ANSI 編碼代表 GBK 編碼;在繁體中文操作系統中,ANSI編碼代表Big5編碼;在日文Windows操作系統中,ANSI 編碼代表 Shift_JIS 編碼。

編碼之間的轉換

UTF-16和UTF-8之間的轉換

1.1.1.1、       Unicode和Utf-8對照表

 


1.1.1.1、       UTF-16轉UTF-8

UTF16和UTF8之間的相互轉換可以通過上圖的轉換表來實現,判斷Unicode碼所在的區間就可以得到這個字符是由幾個字節所組成,之後通過移位來實現,分爲新的多個字節來存儲。

1.1.1.1.1、          步驟(以其中一個字符轉換爲例)

Step1:獲取該字符對應的Unicode碼

Step2:判斷該Unicode碼所在的範圍,根據不同的範圍,來決定存儲它的字節長度.

*如果介於U+00000000 – U+0000007F之間,代表該字符采取一個字節存儲,那麼直接通過這個新字節的unicode碼,即可轉換爲UTF-8碼(這是這裏的一種簡稱,不同的編程語言有不同實現,例如可以用兩個字節來存儲一個字符的信息,解碼時進行判斷,如果發現是UTF-8的多字節實現,那麼將多字節合併後再轉爲一個字符輸出).轉換完畢

 

*如果介於U+00000080 – U+000007FF之間,代表該字符采取兩個字節存儲,那麼將該Unicode碼轉爲二進制,取出高5位(這裏不分大端序和小端序,只以實際的碼爲準,具體實現可以採取移位實現),並加上頭部110,組成第一個字節;再取出低6位(按順序取),加上頭部10,組成第二個字節。然後分別通過兩個新的字節的unicode碼,可以轉換爲相應的UTF-8碼.轉換完畢

 

*如果介於U+00000800 – U+0000FFFF之間,代表該字符采取三個字節存儲,那麼將該Unicode碼轉爲二進制,取出高4位,並加上頭部1110,組成第一個字節;再取出低6位(按順序取),加上頭部10,組成第二個字節;再取出低6位(按順序取),加上頭部10,組成第三個字節。然後分別通過三個新的字節的unicode碼,可以轉換爲相應的UTF-8碼.轉換完畢

 

*如果介於U+00010000 – U+001FFFFF之間,代表該字符采取四個字節存儲(實際上,四個字節或以上存儲的字符是很少的),那麼將該Unicode碼轉爲二進制,取出高3位,並加上頭部11110,組成第一個字節;再取出低6位(按順序取),加上頭部10,組成第二個字節;再取出低6位(按順序取),加上頭部10,組成第三個字節;再取出低6位(按順序取),加上頭部10,組成第四個字節。然後分別通過四個新的字節的unicode碼,可以轉換爲相應的UTF-8碼.轉換完畢

 

*如果介於U+00200000 – U+03FFFFFF,代表該字符采取五個字節存儲,那麼將該Unicode碼轉爲二進制,取出高2位,並加上頭部111110,組成第一個字節;再取出低6位(按順序取),加上頭部10,組成第二個字節;再取出低6位(按順序取),加上頭部10,組成第三個字節;再取出低6位(按順序取),加上頭部10,組成第四個字節;再取出低6位(按順序取),加上頭部10,組成第五個字節。然後分別通過五個新的字節的unicode碼,可以轉換爲相應的UTF-8碼.轉換完畢

 

*如果介於U+04000000 – U+7FFFFFFF,代表該字符采取六個字節存儲,那麼將該Unicode碼轉爲二進制,取出高1位,並加上頭部1111110,組成第一個字節;再取出低6位(按順序取),加上頭部10,組成第二個字節;再取出低6位(按順序取),加上頭部10,組成第三個字節;再取出低6位(按順序取),加上頭部10,組成第四個字節;再取出低6位(按順序取),加上頭部10,組成第五個字節;再取出低6位(按順序取),加上頭部10,組成第六個字節。然後分別通過六個新的字節的unicode碼,可以轉換爲相應的UTF-8碼.轉換完畢

 

1.1.1.1.2、          代碼實現

見示例源碼(以JS爲例子)

<span style="white-space:pre">		</span>/**
		 * @description 將utf-16編碼字符串轉爲utf-8編碼字符串
		 * @param {String} str 傳入的 utf16編碼字符串(javascript內置的就是utf16編碼)
		 * @return {String} utf8編碼的字符串,js打印會有亂碼
		 */
		exports.UTF16StrToUTF8Str = function(str) {
			if (!str) {
				//''字符屬於ascii碼,所以不必擔心不同編碼的轉換問題
				return '';
			}
			//res是用來存放結果的字符數組,最終會轉爲字符串返回
			var res = [],
				len = str.length;
			for (var i = 0; i < len; i++) {
				var code = str.charCodeAt(i);
				if (code > 0x0000 && code <= 0x007F) {
					// 單字節,這裏並不考慮0x0000,因爲它是空字節
					// U+00000000 – U+0000007F  0xxxxxxx
					res.push(str.charAt(i));
				} else if (code >= 0x0080 && code <= 0x07FF) {
					// 雙字節
					// U+00000080 – U+000007FF  110xxxxx 10xxxxxx
					// 110xxxxx
					//0xC0 爲12*16 = 192 二進制爲 11000000
					//0x1F爲 31 二進制   00011111,因爲第一個字節只取5位
					//code 右移六位是因爲從高位開始取得,所以需要將低位的六位留到第二個字節
					var byte1 = 0xC0 | ((code >> 6) & 0x1F);
					// 10xxxxxx
					//0x80爲128 二進制爲 10000000
					//0x3F爲63 二進制位 00111111,因爲只需要取到低位的6位
					var byte2 = 0x80 | (code & 0x3F);
					res.push(
						String.fromCharCode(byte1),
						String.fromCharCode(byte2)
					);
				} else if (code >= 0x0800 && code <= 0xFFFF) {
					// 三字節
					// U+00000800 – U+0000FFFF  1110xxxx 10xxxxxx 10xxxxxx
					// 1110xxxx
					//0xE0 爲224 二進制爲 11100000
					//同理,需要留下 12位給低位
					//0x0F爲15 00001111
					var byte1 = 0xE0 | ((code >> 12) & 0x0F);
					// 10xxxxxx
					//再留6位給低位
					var byte2 = 0x80 | ((code >> 6) & 0x3F);
					// 10xxxxxx
					var byte3 = 0x80 | (code & 0x3F);
					res.push(
						String.fromCharCode(byte1),
						String.fromCharCode(byte2),
						String.fromCharCode(byte3)
					);
				} else if (code >= 0x00010000 && code <= 0x001FFFFF) {
					// 四字節
					// U+00010000 – U+001FFFFF  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
					//同理,需要留下 18位給低位
					//0x07 00000111
					//0xF0  240 11110000
					var byte1 = 0xF0 | ((code >> 18) & 0x07);
					// 10xxxxxx
					//再留12位給低位
					var byte2 = 0x80 | ((code >> 12) & 0x3F);
					//再留6位給低位
					var byte3 = 0x80 | ((code >> 6) & 0x3F);
					// 10xxxxxx
					var byte4 = 0x80 | (code & 0x3F);
					res.push(
						String.fromCharCode(byte1),
						String.fromCharCode(byte2),
						String.fromCharCode(byte3),
						String.fromCharCode(byte4)
					);
				} else if (code >= 0x00200000 && code <= 0x03FFFFFF) {
					// 五字節
					// U+00200000 – U+03FFFFFF  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
					//同理,需要留下 24位給低位
					//0x03 00000011
					//0xF8  248 11111000
					var byte1 = 0xF8 | ((code >> 24) & 0x03);
					// 10xxxxxx
					//再留18位給低位
					var byte2 = 0x80 | ((code >> 18) & 0x3F);
					//再留12位給低位
					var byte3 = 0x80 | ((code >> 12) & 0x3F);
					//再留6位給低位
					var byte4 = 0x80 | ((code >> 6) & 0x3F);
					// 10xxxxxx
					var byte5 = 0x80 | (code & 0x3F);
					res.push(
						String.fromCharCode(byte1),
						String.fromCharCode(byte2),
						String.fromCharCode(byte3),
						String.fromCharCode(byte4),
						String.fromCharCode(byte5)
					);
				} else /** if (code >= 0x04000000 && code <= 0x7FFFFFFF)*/ {
					// 六字節
					// U+04000000 – U+7FFFFFFF  1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
					//同理,需要留下 24位給低位
					//0x01 00000001
					//0xFC  252 11111100
					var byte1 = 0xFC | ((code >> 30) & 0x01);
					// 10xxxxxx
					//再留24位給低位
					var byte2 = 0x80 | ((code >> 24) & 0x3F);
					//再留18位給低位
					var byte3 = 0x80 | ((code >> 18) & 0x3F);
					//再留12位給低位
					var byte4 = 0x80 | ((code >> 12) & 0x3F);
					//再留6位給低位
					var byte5 = 0x80 | ((code >> 6) & 0x3F);
					// 10xxxxxx
					var byte6 = 0x80 | (code & 0x3F);
					res.push(
						String.fromCharCode(byte1),
						String.fromCharCode(byte2),
						String.fromCharCode(byte3),
						String.fromCharCode(byte4),
						String.fromCharCode(byte5),
						String.fromCharCode(byte6)
					);
				}
			}
			return res.join('');
		};


1.1.1.2、       UTF-8轉UTF-16

這是UTF8轉換到UTF16,同樣需要對照轉換表來實現。需要判斷字符的Unicode碼,然後判斷是屬於用幾個字節存儲的,然後分別用對應的字節數合併起來,形成新的字符輸出.

1.1.1.2.1、          步驟(以其中一個字符轉換爲例)

Step1:獲取該字符對應的Unicode碼

Step2:用該碼的二進制和相應的關鍵字節相與,根據上圖,判斷處於那一段區間,來判斷是使用幾個字節存儲字符的,然後分別合併對應的字節數,組成新的字符輸出。

*用該Unicode碼的二進制右移7位後與(11111111)相與,如果得到了0,代表該字符只用了一個字節存儲,所以直接輸出該字符.轉換完畢

 

*用該Unicode碼的二進制右移5位後與(11111111)相與,如果得到了110(6),代表該字符佔用了二個字節,所以分別獲取該字符和下一個字符,然後分別取出本字節的低5位後左移6位和取出下一個字節的低6位(保持不變),將2個字節相或,得到一個新的字節.這個字節就是最終字符的unicode碼,然後轉爲對應的字符輸出. 轉換完畢

 

*用該Unicode碼的二進制右移4位後與(11111111)相與,如果得到了1110(14),代表該字符佔用了三個字節,所以分別獲取該字符和下一個字符和下下個字符,然後分別取出本字節的低4位後左移12位和取出下一個字節的低6位後左移6位和取出下下一個字節的低6位(保持不變),將3個字節相或,得到一個新的字節.這個字節就是最終字符的unicode碼,然後轉爲對應的字符輸出. 轉換完畢

 

*用該Unicode碼的二進制右移3位後與(11111111)相與,如果得到了11110(30),代表該字符佔用了四個字節,所以分別獲取該字符和下一個字符和下下個字符和下下下個字符,然後分別取出本字節的低3位後左移18位取出下一個字節的低6位後左移12位和和取出下下一個字節的低6位後左移6位和取出下下下一個字節的低6位(保持不變),將4個字節相或,得到一個新的字節.這個字節就是最終字符的unicode碼,然後轉爲對應的字符輸出. 轉換完畢

 

*用該Unicode碼的二進制右移2位後與(11111111)相與,如果得到了111110(62),代表該字符佔用了五個字節,所以分別獲取該字符和下一個字符和下下個字符和下下下個字符和下下下下個字符,然後分別取出本字節的低2位後左移24位和取出下一個字節的低6位後左移18位和取出下下一個字節的低6位後左移12位和和取出下下下一個字節的低6位後左移6位和取出下下下下一個字節的低6位(保持不變),將5個字節相或,得到一個新的字節.這個字節就是最終字符的unicode碼,然後轉爲對應的字符輸出. 轉換完畢

 

*用該Unicode碼的二進制右移1位後與(11111111)相與,如果得到了1111110(126),代表該字符佔用了六個字節,所以分別獲取該字符和下一個字符和下下個字符和下下下個字符和下下下下個字符和下下下下下個字符,然後分別取出本字節的低1位後左移30位和取出下一個字節的低6位後左移24位和取出下下一個字節的低6位後左移18位和取出下下下一個字節的低6位後左移12位和和取出下下下下一個字節的低6位後左移6位和取出下下下下下一個字節的低6位(保持不變),將6個字節相或,得到一個新的字節.這個字節就是最終字符的unicode碼,然後轉爲對應的字符輸出. 轉換完畢

1.1.1.2.2、          代碼實現

見示例源碼(以JS爲例子)

<span style="white-space:pre">		</span>/**
		 * @description UTF8編碼字符串轉爲UTF16編碼字符串
		 * @param {String} str utf8編碼的字符串
		 * @return {String} utf16編碼的字符串,可以直接被js用來打印
		 */
		exports.UTF8StrToUTF16Str = function(str) {
			if (!str) {
				return '';
			}
			//res是用來存放結果的字符數組,最終會轉爲字符串返回
			var res = [],
				len = str.length;
			for (var i = 0; i < len; i++) {
				//獲得對應的unicode碼
				var code = str.charCodeAt(i);
				// 對第一個字節進行判斷
				if (((code >> 7) & 0xFF) == 0x0) {
					//0xFF 255 11111111,代表只取前8位
					//右移7位,如果是只剩下0了,代表這個是單字節
					// 單字節
					// 0xxxxxxx
					res.push(str.charAt(i));
				} else if (((code >> 5) & 0xFF) == 0x6) {
					// 雙字節 110開頭  
					// 110xxxxx 10xxxxxx
					//需要用到下一個字節
					var code2 = str.charCodeAt(++i);
					//0x1F 31 00011111
					//取到第一個字節的後5位,然後左移6位(這6位留給第二個字節的低6位),由於js是number型,所以不必擔心溢出
					var byte1 = (code & 0x1F) << 6;
					//0x3F 63  00111111
					var byte2 = code2 & 0x3F;
					//或運算,因爲第一個字節第六位沒有,第二個字節只有低6位,所以算是結合了
					var utf16 = byte1 | byte2;
					res.push(String.fromCharCode(utf16));
				} else if (((code >> 4) & 0xFF) == 0xE) {
					// 三字節 1110開頭
					// 1110xxxx 10xxxxxx 10xxxxxx
					var code2 = str.charCodeAt(++i);
					var code3 = str.charCodeAt(++i);
					//和00001111與後, 左移12位
					var byte1 = (code & 0x0F) << 12;
					//和00111111與後,左移6位
					var byte2 = (code2 & 0x3F) << 6;
					//和00111111與
					var byte3 = code3 & 0x3F
					var utf16 = byte1 | byte2 | byte3;
					res.push(String.fromCharCode(utf16));
				} else if (((code >> 3) & 0xFF) == 0x1E) {
					// 四字節 11110開頭
					// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
					var code2 = str.charCodeAt(++i);
					var code3 = str.charCodeAt(++i);
					var code4 = str.charCodeAt(++i);
					//和00000111與後, 左移18位
					var byte1 = (code & 0x07) << 18;
					//和00111111與後,左移12位
					var byte2 = (code2 & 0x3F) << 12;
					//和00111111與後,左移6位
					var byte3 = (code3 & 0x3F) << 6;
					//和00111111與
					var byte4 = code4 & 0x3F
					var utf16 = byte1 | byte2 | byte3 | byte4;
					res.push(String.fromCharCode(utf16));
				} else if (((code >> 2) & 0xFF) == 0x3E) {
					// 五字節 111110開頭
					// 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
					var code2 = str.charCodeAt(++i);
					var code3 = str.charCodeAt(++i);
					var code4 = str.charCodeAt(++i);
					var code5 = str.charCodeAt(++i);
					//和00000011與後, 左移24位
					var byte1 = (code & 0x03) << 24;
					//和00111111與後,左移18位
					var byte2 = (code2 & 0x3F) << 18;
					//和00111111與後,左移12位
					var byte3 = (code3 & 0x3F) << 12;
					//和00111111與後,左移6位
					var byte4 = (code4 & 0x3F) << 6;
					//和00111111與
					var byte5 = code5 & 0x3F
					var utf16 = byte1 | byte2 | byte3 | byte4 | byte5;
					res.push(String.fromCharCode(utf16));
				} else /** if (((code >> 1) & 0xFF) == 0x7E)*/ {
					// 六字節 1111110開頭
					// 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
					var code2 = str.charCodeAt(++i);
					var code3 = str.charCodeAt(++i);
					var code4 = str.charCodeAt(++i);
					var code5 = str.charCodeAt(++i);
					var code6 = str.charCodeAt(++i);
					//和00000001與後, 左移30位
					var byte1 = (code & 0x01) << 30;
					//和00111111與後,左移24位
					var byte2 = (code2 & 0x3F) << 24;
					//和00111111與後,左移18位
					var byte3 = (code3 & 0x3F) << 18;
					//和00111111與後,左移12位
					var byte4 = (code4 & 0x3F) << 12;
					//和00111111與後,左移6位
					var byte5 = (code5 & 0x3F) << 6;
					//和00111111與
					var byte6 = code6 & 0x3F
					var utf16 = byte1 | byte2 | byte3 | byte4 | byte5 | byte6;
					res.push(String.fromCharCode(utf16));
				}
			}
			return res.join('');
		};



Unicode和GBK之間的轉換

這裏以UTF-16和GBK之間的轉換爲例(示例用的Javascript語言,內置UTF-16編碼)

1.1.1.1、       UTF-16轉GBK

UTF-16轉爲GBK,需要先得知兩者之間的映射表才行.(可以百度搜索Unicode和GBK之間的轉換表),然後根據兩者的映射關係,進行一一對應轉換.

1.1.1.1.1、          步驟(以其中一個字符轉換爲例)

Step1:獲取該字符對應的Unicode碼

Step2:判斷該Unicode的範圍,如果是普通的ASCII碼,則不進行轉換,如果是大於127小於等於255的(標準碼範圍的,GBK兼容ISO-8859標準碼的),根據映射表,轉爲對應的GBK碼,如果是大於255的(大於255代表一個字節裝不下了,所以這時候不再是兼容模式,而是GBK的存儲模式,需要兩個字節來存儲),就將改碼轉換爲GBK獨特的雙字節存儲方式來存儲(高字節區存儲分區號,低字節去存儲碼號).轉換完畢

1.1.1.1.2、          代碼實現

見示例源碼(js爲例)

<span style="white-space:pre">		</span>/**
		 * @description 將utf16編碼的字符串(js內置編碼)轉爲GBK編碼的字符串
		 * @param {String} str utf16編碼的字符串(js內置)
		 * @return {String} 轉換後gbk編碼的字符串
		 */
		exports.UTF16StrToGBKStr = function(str) {
			if (!str) {
				return '';
			}
			//res是用來存放結果的字符數組,最終會轉爲字符串返回
			var res = [],
				len = str.length;
			for (var i = 0; i < len; i++) {
				//獲得對應的unicode碼
				var code = str.charCodeAt(i);
				if (code < 0) {
					code += 65536;
				}
				if (code > 127) {
					code = UniCode2GBKCode(code);
				}
				if (code > 255) {
					//gbk中,如果是漢字的,需要兩位來表示
					//對所收錄字符進行了“分區”處理,分爲若干區,每區若干碼位
					//第一個字節爲“高字節”,對應不同分區
					//第二個字節爲“低字節”,對應每個區的不同碼位
					var varlow = code & 65280;
					//取得低位				
					varlow = varlow >> 8;
					//取得高位
					var varhigh = code & 255;
					res.push(String.fromCharCode(varlow));
					res.push(String.fromCharCode(varhigh));
				} else {
					res.push(String.fromCharCode(code));
				}
			}
			return res.join('');
		};
<span style="white-space:pre">		</span>/**
		 * @description 將unicode通過查錶轉換,轉爲gbk的code
		 * @param {Number} chrCode 字符unicode編碼
		 */
		function UniCode2GBKCode(chrCode) {
<span style="white-space:pre">			</span>//這裏<span style="font-family: Arial, Helvetica, sans-serif;">UnicodeCharTable和</span><span style="font-family: Arial, Helvetica, sans-serif;">GBKCharTable由於太長了,就沒有給出了,可以下載源碼例子查看</span>
			var chrHex = chrCode.toString(16);
			chrHex = "000" + chrHex.toUpperCase();
			chrHex = chrHex.substr(chrHex.length - 4);
			var i = UnicodeCharTable.indexOf(chrHex);
			if (i != -1) {
				chrHex = GBKCharTable.substr(i, 4);
			} 
			return parseInt(chrHex, 16)
		};


2.1.1.1.1、          GBK轉UTF-16

GBK轉爲UTF-16,也需要根據Unicode和GBK之間的映射表,然後根據兩者的映射關係,進行一一對應轉換.

2.1.1.1.2、          步驟

Step1:獲取該字符對應的Unicode碼

Step2:判斷該Unicode的範圍,如果是普通的ASCII碼,則不進行轉換,直接輸出,否則,需要根據GBK和Unicode的對應關係,轉換爲Unicode碼,需要注意的是,這裏由於GBK採取雙字節編碼的,所以需要用到兩個字節,轉碼時需要將編碼時的運算逆轉,轉爲Unicode碼,然後再輸出相應的字符.轉換完畢

 

2.1.1.1.3、          代碼實現

三、 見示例源碼(js)

<span style="white-space:pre">		</span>/**
		 * @description將 gbk的對應的code通過查錶轉換,轉爲unicode
		 * @param {Number} chrCode gbk字符對應的編碼
		 */
		function GBKCode2UniCode(chrCode) {
<span style="white-space:pre">			</span><span style="font-family: Arial, Helvetica, sans-serif;">//這裏</span><span style="font-family: Arial, Helvetica, sans-serif;">UnicodeCharTable和</span><span style="font-family: Arial, Helvetica, sans-serif;">GBKCharTable由於太長了,就沒有給出了,可以下載源碼例子查看</span><span style="white-space:pre">
</span>			//以16進制形式輸出字符串
			var chrHex = chrCode.toString(16);
			//
			chrHex = "000" + chrHex.toUpperCase();
			//
			chrHex = chrHex.substr(chrHex.length - 4);

			var i = GBKCharTable.indexOf(chrHex);

			if (i != -1) {
				chrHex = UnicodeCharTable.substr(i, 4);
			} 
			return parseInt(chrHex, 16)
		};
<span style="white-space:pre">		</span>/**
		 * @description 將GBK編碼的字符串轉爲utf16編碼的字符串(js內置編碼)
		 * @param {String} str GBK編碼的字符串
		 * @return {String} 轉化後的utf16字符串
		 */
		exports.GBKStrToUTF16Str = function(str) {
			if (!str) {
				return '';
			}
			//res是用來存放結果的字符數組,最終會轉爲字符串返回
			var res = [],
				len = str.length;
			for (var i = 0; i < len; i++) {
				//獲得對應的unicode碼
				var code = str.charCodeAt(i);
				//如果不是ASCII碼
				if (code > 127) {
					//轉爲unicode	
					//這裏左移8位是因爲編碼時,被右移了8位
					code = GBKCode2UniCode((code << 8) + str.charCodeAt(++i));		
				} else {
					//普通的ASCII碼,什麼都不做				
				}
				res.push(String.fromCharCode(code));
			}
			return res.join('');
		};


 

編碼之間的轉換


Base64編碼

Base64編碼要求把3個8位字節(3*8=24)轉化爲4個6位的字節(4*6=24),之後在6位的前面補兩個0,形成8位一個字節的形式。由於2的6次方爲64,所以每6個位爲一個單元,對應某個可打印字符。當原數據不是3的整數倍時,如果最後剩下兩個輸入數據,在編碼結果後加1個“=;如果最後剩下一個輸入數據,編碼結果後加2個“=;如果沒有剩下任何數據,就什麼都不要加,這樣纔可以保證資料還原的正確性。

Base64解碼


解碼是編碼的逆過程,先看後面補了幾個“=”號,最多隻可能補2個“=”號。一個“=”相當於補了2個0,所以去掉後面補的0後,再按8位展開,即可還原。

轉碼對照表

每6個單元高位補2個零形成的字節位於0~63之間,通過在轉碼錶中查找對應的可打印字符。“=”用於填充。如下圖所示爲轉碼錶。


示例

以”Word”字符串的編碼和解碼爲例。

1.1.1.1、       編碼

原始字符

W

o

r

d(由於不是3的倍數,所以補0了)

ASCII碼

87

111

114

100

8bit字節

01010111

01101111

01110010

01100100

00000000

00000000

6bit字節

010101

110110

111101

110010

011001

000000

000000

000000

B64十進制

21

54

61

50

25

0

(注意,這裏有兩位是d裏面的,所以是正常的0)

異常

(注意這裏不能按正規的0來算)

異常

(需要補上=號)

對應編碼

V

2

9

y

Z

A

=

=

所以’Word’的編碼結果是V29yZA==

1.1.1.2、       解碼

原始編碼

V

2

9

y

Z

A

=

=

B64十進制

21

54

61

50

25

0

異常

異常

6bit字節

010101

110110

111101

110010

011001

000000

000000

000000

8bit字節

01010111

01101111

01110010

01100100

00000000

00000000

ASCII碼

87

111

114

100

異常

異常

對應字符

W

o

r

d

由此可見,解碼過程就是編碼過程的逆過程。

源碼實現

需要注意的是,實際編碼時需要注意程序內部的編碼,例如Javascript內置的是UTF-16編碼,所以如果編碼成GBK或UTF-8時需要經過一定的轉換.

詳情見示例源碼

<span style="white-space:pre">		</span>/**
		 * @description 創建一個base64對象
		 */
		(function(base64) {
			/**
			 * Base64編碼要求把3個8位字節(3*8=24)轉化爲4個6位的字節(4*6=24),
			 * 之後在6位的前面補兩個0,形成8位一個字節的形式。
			 * 由於2的6次方爲64, 所以每6個位爲一個單元, 對應某個可打印字符。
			 * 當原數據不是3的整數倍時, 如果最後剩下兩個輸入數據,
			 * 在編碼結果後加1個“=;如果最後剩下一個輸入數據,編碼結果後加2個“=;
			 * 如果沒有剩下任何數據,就什麼都不要加,這樣纔可以保證資料還原的正確性。
			 */
			/**
			 * base64轉碼錶,最後一個=號是專門用來補齊的
			 */
			var keyTable = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
			/**
			 * @description 將一個目標字符串編碼爲base64字符串
			 * @param {String} str 傳入的目標字符串
			 * 可以是任何編碼類型,傳入什麼類型就輸出成了什麼樣的編碼
			 * 由於js內置是utf16編碼,而服務器端一般不使用這種,
			 * 所以傳入的編碼一般是採取utf8或gbk的編碼
			 * @return {String} 編碼後的base64字符串
			 */
			function encodeBase64(str) {
				if (!str) {
					return '';
				}
				var i = 0; // 遍歷索引
				var len = str.length;
				var res = [];
				var c1, c2, c3 = '';
				//用來存對應的位置
				var enc1, enc2, enc3, enc4 = '';
				while (i < len) {
					c1 = str.charCodeAt(i++) & 0xFF;
					c2 = str.charCodeAt(i++);
					c3 = str.charCodeAt(i++);
					enc1 = c1 >> 2;
					enc2 = ((c1 & 0x3) << 4) | ((c2 >> 4) & 0x0F);
					enc3 = ((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6);
					enc4 = c3 & 0x3F;
					//專門用來補齊=號的
					if (isNaN(c2)) {
						enc3 = enc4 = 0x40;
					} else if (isNaN(c3)) {
						enc4 = 0x40;
					}
					res.push(keyTable.charAt(enc1));
					res.push(keyTable.charAt(enc2));
					res.push(keyTable.charAt(enc3));
					res.push(keyTable.charAt(enc4));
					c1 = c2 = c3 = "";
					enc1 = enc2 = enc3 = enc4 = "";
				}
				return res.join('');
			};
			/**
			 * @description 解碼base64字符串,還原爲編碼前的結果
			 * @param {String} str 傳入的目標字符串
			 * 可以是任何編碼類型,傳入什麼類型就輸出成了什麼樣的編碼
			 * 由於js內置是utf16編碼,而服務器端一般不使用這種,
			 * 所以傳入的編碼一般是採取utf8或gbk的編碼
			 * @return {String} 編碼後的base64字符串
			 */
			function decodeBase64(str) {
				if (!str) {
					return '';
				}
				//這裏要判斷目標字符串是不是base64型,如果不是,直接就不解碼了
				//兩層判斷
				if (str.length % 4 != 0) {
					return "";
				}
				var base64test = /[^A-Za-z0-9\+\/\=]/g;
				if (base64test.exec(str)) {
					return "";
				}
				var len = str.length;
				var i = 0;
				var res = [];
				var code1, code2, code3, code4;
				while (i < len) {
					code1 = keyTable.indexOf(str.charAt(i++));
					code2 = keyTable.indexOf(str.charAt(i++));
					code3 = keyTable.indexOf(str.charAt(i++));
					code4 = keyTable.indexOf(str.charAt(i++));

					c1 = (code1 << 2) | (code2 >> 4);
					c2 = ((code2 & 0xF) << 4) | (code3 >> 2);
					c3 = ((code3 & 0x3) << 6) | code4;

					res.push(String.fromCharCode(c1));

					if (code3 != 64) {
						res.push(String.fromCharCode(c2));
					}
					if (code4 != 64) {
						res.push(String.fromCharCode(c3));
					}
				}
				return res.join('');
			};
			/**
			 * @description 將utf16字符串轉爲utf8編碼類型的base64編碼
			 * 注意:js內置的編碼是utf16型,所以傳入的是utf16型碼
			 * @param {String} str 傳入的utf16編碼
			 * @return {String} 編碼後的utf8型base64字符串
			 */
			base64.encode_Utf8 = function(str) {
				// 轉成UTF8
				var utf8 = exports.UTF16StrToUTF8Str(str);
				return encodeBase64(utf8);
			};
			/**
			 * @description utf8編碼的base64解密,解密成爲js內置的utf16編碼
			 * 注意:這裏會講傳入的字符串當成utf8型,如果類型不匹配,就會產生錯誤結果
			 * @param {String} str 傳入的utf8編碼型base64字符串
			 * @return {String} 解碼後的utf16字符串
			 */
			base64.decode_Utf8 = function(str) {
				var decodeStr = decodeBase64(str);
				// 轉成UTF16
				return exports.UTF8StrToUTF16Str(decodeStr);
			};
			/**
			 * @description 將utf16字符串轉爲GBK編碼類型的base64編碼
			 * 注意:js內置的編碼是utf16型,所以傳入的是utf16型碼
			 * @param {String} str 傳入的utf16編碼
			 * @return {String} 編碼後的gbk型base64字符串
			 */
			base64.encode_GBK = function(str) {
				// 轉成GBK
				var GBK = exports.UTF16StrToGBKStr(str);
				return encodeBase64(GBK);
			};
			/**
			 * @description GBK編碼的base64解密,解密成爲js內置的utf16編碼
			 * 注意:這裏會講傳入的字符串當成GBK型,如果類型不匹配,就會產生錯誤結果
			 * @param {String} str 傳入的GBK編碼型base64字符串
			 * @return {String} 解碼後的utf16字符串
			 */
			base64.decode_GBK = function(str) {
				var decodeStr = decodeBase64(str);
				// 轉成UTF16
				return exports.GBKStrToUTF16Str(decodeStr);
			};
		})(exports.Base64 = {});
		return exports;
	});



源碼項目


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章