在軟體的編碼和實現中,我們可能會碰到個 一個比較頭疼的問題--編碼,不同字元間的編碼和解碼,你確定瞭解各種字元的編碼嗎?一個朋友問到了我這 個問題,我雖然能回答一兩個出來,但是感覺已經有點模糊,混亂了,在網上搜了搜,在書上翻了翻,總結一下吧。首先按照字元編碼的歷程來看:
- ASCII
我們需要了解的最早編碼是ASCII碼。它用7個二進位制位來表示,由於那個時期生產的大多數計算機使用8位大小的位元組,因此使用者不僅可以存放所有 可能的ASCII字元,而且有整整一位空餘下來。如果你技藝高超,可以將該位用做自己離奇的目的:WordStar中那個發暗的燈泡實際上設定這個高位, 以指示一個單詞中的最後一個字母,同時這也宣示了WordStar只能用於英語文字。
由於位元組有多達8位的空間,因此許多人在想:“呀!我們 可以把128~255之間的編碼用做個人的應用目的。”問題在於,同時產生這種想法的人相當多,而且在128~255之間的各個位置上應該存放什麼這一問 題上,真是仁者見仁智者見智。事實上,只要人們開始在美國以外的地方購買計算機,那麼各種各樣的不同OEM字符集都會進入規劃設計行列,並且各人都會根據 自己的需要使用高位的128個字元。如此一來,甚至在同語種的文件之間就不容易實現互換。 ASCII可被擴充套件,最優秀的擴充套件方案是ISO 8859-1,通常稱之為Latin-1。Latin-1包括了足夠的附加字符集來寫基本的西歐語言。
最後,這個人人蔘與的OEM終於以ANSI標準的形式形成檔案。在ANSI標準中,每個人都認同如何使用低端的128個編碼,這與ASCII相當一致。不過,根據所在國籍的不同,處理編碼128以上的字元有許多不同的方式。這些不同的系統稱為內碼表。
同時,甚至更為令人頭疼的事情正在逐步上演,亞洲國家的字元表有成千上萬個字元,這樣的字元表是用8位二進位制無法表示的。該問題的解決通常有賴於稱為DBCS(double byte character set,雙位元組字符集)的繁雜字元系統。
不過,仍然需要指出一點,多數人還是姑且認為一個位元組就是一個字元,以及一個字元就是8個二進位制位,並且只要確保不將字串從一臺計算機移植到另一臺計 算機,或者說一種以上的語言,那麼這幾乎總是可以湊合。當然,只要一進入Internet,從一臺計算機向另一臺計算機移植字串就成為家常便飯了,而各 種複雜狀況也隨之呈現出來。令人欣慰的是,Unicode隨即問世了。
作用:表語英語及西歐語言。
位數:ASCII是用7位表示的,能表示128個字元;其擴充套件使用8位表示,表示256個字元。
範圍:ASCII從00到7F,擴充套件從00到FF。
2.iso8859-1
屬於單位元組編碼,最多能表示的字元範圍是0-255,應用於英文系列。比如,字母'a'的編碼為0x61=97。
很明顯,iso8859-1編碼表示的字元範圍很窄,無法表示中文字元。但是,由於是單位元組編碼,和計算機最基礎的表示單位一致,所以很多時候,仍 舊使用iso8859-1編碼來表示。而且在很多協議上,預設使用該編碼。比如,雖然"中文"兩個字不存在iso8859-1編碼,以gb2312編碼為 例,應該是"d6d0 cec4"兩個字元,使用iso8859-1編碼的時候則將它拆開為4個位元組來表示:"d6 d0 ce c4"(事實上,在進行儲存的時候,也是以位元組為單位處理的)。而如果是UTF編碼,則是6個位元組"e4 b8 ad e6 96 87"。很明顯,這種表示方法還需要以另一種編碼為基礎。
作用:擴充套件ASCII,表示西歐、希臘語等。
位數:8位,
範圍:從00到FF,相容ASCII字符集。
- GB碼字符集
全稱是GB2312-80《資訊交換用漢字編碼字符集基本集》,1980年釋出,是中文資訊處理的國家標準,在大陸及海外使用簡體中文的地區(如新加坡 等)是強制使用的唯一中文編碼。P-Windows3.2和蘋果OS就是以GB2312為基本漢字編碼, Windows 95/98則以GBK為基本漢字編碼、但相容支援GB2312。
雙位元組編碼
範圍:A1A1~FEFE
A1-A9:符號區,包含682個符號
B0-F7:漢字區,包含6763個漢字
4.GB2312字符集
GB2312(1980年)一共收錄了7445個字元,包括6763個漢字和682個其它符號。漢字區的內碼範圍高位元組從B0-F7,低位元組從 A1-FE,佔用的碼位是72*94=6768。其中有5個空位是D7FA-D7FE。GB2312-80中共收錄了7545個字元,用兩個位元組編碼一個 字元。每個字元最高位為0。GB2312-80編碼簡稱國標碼。
GB2312支援的漢字太少。1995年的漢字擴充套件規範GBK1.0收錄了21886個符號,它分為漢字區和圖形符號區。漢字區包括21003個字元。
作用:國家簡體中文字符集,相容ASCII。
位數:使用2個位元組表示,能表示7445個符號,包括6763個漢字,幾乎覆蓋所有高頻率漢字。
範圍:高位元組從A1到F7, 低位元組從A1到FE。將高位元組和低位元組分別加上0XA0即可得到編碼。
- GB12345-90字符集
1990年制定了繁體字的編碼標準GB12345-90《資訊交換用漢字編碼字符集第一輔助集》,目的在於規範必須使用繁體字的各種場合,以及古籍整理 等。該標準共收錄6866個漢字(比GB2312多103個字,其它廠商的字型檔大多不包括這些字),純繁體的字大概有2200餘個。
雙位元組編碼
範圍:A1A1~FEFE
A1-A9:符號區,增加豎排符號
B0-F9:漢字區,包含6866個漢字
6.GBK字符集
GBK編碼(Chinese Internal Code Specification)是中國大陸制訂的、等同於UCS的新的中文編碼擴充套件國家標準。gbk編碼能夠用來同時表示繁體字和簡體字,而gb2312只 能表示簡體字,gbk是相容gb2312編碼的。GBK工作小組於1995年10月,同年12月完成GBK規範。該編碼標準相容GB2312,共收錄漢字 21003個、符號883個,並提供1894個造字碼位,簡、繁體字融於一庫。Windows95/98簡體中文版的字型檔表層編碼就採用的是GBK,通過 GBK與UCS之間一一對應的碼錶與底層字型檔聯絡。
英文名:Chinese Internal Code Specification
中文名:漢字內碼擴充套件規範1.0版
雙位元組編碼,GB2312-80的擴充,在碼位上和GB2312-80相容
範圍:8140~FEFE(剔除xx7F)共23940個碼位。包含21003個漢字,包含了ISO/IEC 10646-1中的全部中日韓漢字
作用:它是GB2312的擴充套件,加入對繁體字的支援,相容GB2312。
位數:使用2個位元組表示,可表示21886個字元。
範圍:高位元組從81到FE,低位元組從40到FE。
- BIG5字符集
是目前臺灣、香港地區普遍使用的一種繁體漢字的編碼標準,包括440個符號,一級漢字5401個、二級漢字7652個,共計13060個漢字。BIG5又 稱大五碼或五大碼,1984年由臺灣財團法人資訊工業策進會和五間軟體公司巨集碁 (Acer)、神通 (MiTAC)、佳佳、零壹 (Zero One)、大眾 (FIC)創立,故稱大五碼。Big5碼的產生,是因為當時臺灣不同廠商各自推出不同的編碼,如倚天碼、IBM PS55、王安碼等,彼此不能相容;另一方面,臺灣政府當時尚未推出官方的漢字編碼,而中國大陸的GB2312編碼亦未有收錄繁體中文字。
Big5字符集共收錄13,053箇中文字,該字符集在台灣使用。耐人尋味的是該字符集重複地收錄了兩個相同的字:“兀”(0xA461及0xC94A)、“嗀”(0xDCD1及0xDDFC)。
Big5碼使用了雙位元組儲存方法,以兩個位元組來編碼一個字。第一個位元組稱為“高位位元組”,第二個位元組稱為“低位位元組”。高位位元組的編碼範圍0xA1-0xF9,低位位元組的編碼範圍0x40-0x7E及0xA1-0xFE。
儘管Big5碼內包含一萬多個字元,但是沒有考慮社會上流通的人名、地名用字、方言用字、化學及生物科等用字,沒有包含日文平假名及片假字母。
例如臺灣視“著”為“著”的異體字,故沒有收錄“著”字。康熙字典中的一些部首用字(如“亠”、“疒”、“辵”、“癶”等)、常見的人名用字(如“堃”、“煊”、“栢”、“喆”等) 也沒有收錄到Big5之中。
8.GB18030字符集
GB 18030-2000全稱是《資訊科技資訊交換用漢字編碼字符集基本集的擴充》,由資訊產業部和原國家質量技術監督局於2000年3月17日聯合釋出,作為國家強制性標準自發布之日起實施。
為了適應資訊處理技術快速發展的需要,1998年10月,由資訊產業部電子四所、北京大學計算機技術研究所、北大方正集團、新天地公司、四通新世紀公司、 中科院軟體所、長城軟體公司、中軟總公司、金山軟體公司和聯想公司的技術人員組成標準起草組。在標準研製過程中,全國資訊科技標準化技術委員會多次召集標 準起草組和知名公司對標準草案進行充分地研究論證,並且特邀了微軟公司、惠普公司、Sun公司和IBM公司等參加,廣泛徵求意見。標準起草組經過反覆斟酌 和驗證,提出了標準制定原則——與GB 2312資訊處理交換碼所對應的事實上的內碼標準相容,在字彙上支援GB 13000.1的全部中、日、韓(CJK)統一漢字字元和全部CJK擴充A的字元,並且確定了編碼體系和27484個漢字,形成相容性、擴充套件性、前瞻性兼 備的方案。
該標準採用單位元組、雙位元組和四位元組三種方式對字元編碼。
作用:它解決了中文、日文、朝鮮語等的編碼,相容GBK。
位數:它採用變位元組表示(1 ASCII,2,4位元組)。可表示27484個文字。
範圍:1位元組從00到7F; 2位元組高位元組從81到FE,低位元組從40到7E和80到FE;4位元組第一三位元組從81到FE,第二四位元組從30到39。
9.通用字符集(UCS)字符集
ISO/IEC 10646-1 [ISO-10646]定義了一種多於8位元位元組的字符集,稱作通用字符集(UCS),它包含了世界上大多數可書寫的字元系統。已定義了兩種多8位元位元組 編碼,對每一個字元采用四個8位元位元組編碼的稱為UCS-4,對每一個字元采用兩個8位元位元組編碼的稱為UCS-2。它們僅能夠對UCS的前64K字元進 行編址,超出此範圍的其它部分當前還沒有分配編址。
作用:國際標準 ISO 10646 定義了通用字符集 (Universal Character Set)。它是與UNICODE同類的組織,UCS-2和UNICODE相容。
位數:它有UCS-2和UCS-4兩種格式,分別是2位元組和4位元組。
範圍:目前,UCS-4只是在UCS-2前面加了0x0000。
10.Unicode字符集
Unicode字符集(簡稱為UCS),國際標準組織於1984年4月成立ISO/IEC JTC1/SC2/WG2工作組,針對各國文字、符號進行統一性編碼。1991年美國跨國公司成立Unicode Consortium,並於1991年10月與WG2達成協議,採用同一編碼字集。目前Unicode是採用16位編碼體系,其字符集內容與 ISO10646的BMP(Basic Multilingual Plane)相同。Unicode於1992年6月通過DIS(Draf International Standard),目前版本V2.0於1996公佈,內容包含符號6811個,漢字20902個,韓文拼音11172個,造字區6400個,保留 20249個,共計65534個。Unicode編碼後的大小是一樣的.例如一個英文字母 "a" 和 一個漢字 "好",編碼後都是佔用的空間大小是一樣的,都是兩個位元組!
Unicode可以用來表示所有語言的字元,而且是定長雙位元組(也有四位元組的)編碼,包括英文字母在內。所以可以說它是不相容iso8859-1編碼的, 也不相容任何編碼。不過,相對於iso8859-1編碼來說,uniocode編碼只是在前面增加了一個0位元組,比如字母'a'為"00 61"。
需要說明的是,定長編碼便於計算機處理(注意GB2312/GBK不是定長編碼),而unicode又可以用來表示所有字元,所以在很多軟體內部是使用unicode編碼來處理的,比如java。
UNICODE字符集有多個編碼方式,分別是UTF-8,UTF-16,UTF-32和UTF-7編碼。
UTF-8
UTF:UCS Transformation Format.考慮到unicode編碼不相容iso8859-1編碼,而且容易佔用更多的空間:因為對於英文字母,unicode也需要兩個位元組來表 示。所以unicode不便於傳輸和儲存。因此而產生了utf編碼,utf編碼相容iso8859-1編碼,同時也可以用來表示所有語言的字元,不 過,utf編碼是不定長編碼,每一個字元的長度從1-6個位元組不等。另外,utf編碼自帶簡單的校驗功能。一般來講,英文字母都是用一個位元組表示,而漢字 使用三個位元組。
注意,雖然說utf是為了使用更少的空間而使用的,但那只是相對於unicode編碼來說,如果已經知道是漢字,則使用GB2312/GBK無疑是 最節省的。不過另一方面,值得說明的是,雖然utf編碼對漢字使用3個位元組,但即使對於漢字網頁,utf編碼也會比unicode編碼節省,因為網頁中包 含了很多的英文字元。
UTF8編碼後的大小是不一定,例如一個英文字母"a" 和 一個漢字 "好",編碼後佔用的空間大小就不樣了,前者是一個位元組,後者是三個位元組!編碼的方法是從低位到高位。黃色為標誌位其它著色為了顯示其,編碼後的位置。
UTF-16
採用2 位元組,Unicode中不同部分的字元都同樣基於現有的標準。這是為了便於轉換。從 0x0000到0x007F是ASCII字元,從0x0080到0x00FF是ISO-8859-1對ASCII的擴充套件。希臘字母表使用從0x0370到 0x03FF 的程式碼,斯拉夫語使用從0x0400到0x04FF的程式碼,美國使用從0x0530到0x058F的程式碼,希伯來語使用從0x0590到0x05FF的代 碼。中國、日本和韓國的象形文字(總稱為CJK)佔用了從0x3000到0x9FFF的程式碼;
由於0x00在c語言及作業系統檔名等中有特殊意義,故很多情況下需要UTF-8編碼儲存文字,去掉這個0x00。舉例如下:
UTF-16: 0x0080 = 0000 0000 1000 0000
UTF-8: 0xC280 = 1100 0010 1000 0000
UTF-32
採用4位元組。
UTF-7
A Mail-Safe Transformation Format of Unicode(RFC1642)。這是一種使用 7 位 ASCII 碼對 Unicode 碼進行轉換的編碼。它的設計目的仍然是為了在只能傳遞 7 為編碼的郵件閘道器中傳遞資訊。 UTF-7 對英語字母、數字和常見符號直接顯示,而對其他符號用修正的 Base64 編碼。符號 + 和 - 號控制編碼過程的開始和暫停。所以亂碼中如果夾有英文單詞,並且相伴有 + 號和 - 號,這就有可能是 UTF-7 編碼。
作用:為世界650種語言進行統一編碼,相容ISO-8859-1。
位數:UNICODE字符集有多個編碼方式,分別是UTF-8,UTF-16和UTF-32。
很多人以為UTF-8等和Unicode都是字符集或都是編碼方式,其實這是誤區。
到以上為止,大部分常用的字符集已經基本列舉完畢,再看一些其他的編碼方式:
MIME 編碼
MIME 是“多用途網際郵件擴充協議”的縮寫,在 MIME 協議之前,郵件的編碼曾經有過 UUENCODE 等編碼方式 ,但是由於 MIME 協議演算法簡單,並且易於擴充套件,現在已經成為郵件編碼方式的主流,不僅是用來傳輸 8 bit 的字元,也可以用來傳送二進位制的檔案 ,如郵件附件中的影象、音訊等資訊,而且擴充套件了很多基於MIME 的應用。從編碼方式來說,MIME 定義了兩種編碼方法Base64與QP(Quote-Printable)。
Base64
按照RFC2045的定義,Base64被定義為:Base64內容傳送編碼被設計用來把任意序列的8位位元組描述為一種不易被人直接識別的形式。
為什麼要使用Base64?
在設計這個編碼的時候,我想設計人員最主要考慮了3個問題:
1.是否加密?
2.加密演算法複雜程度和效率
3.如何處理傳輸?
加密是肯定的,但是加密的目的不是讓使用者傳送非常安全的Email。這種加密方式主要就是“防君子不防小人”。即達到一眼望去完全看不出內容即可。
基 於這個目的加密演算法的複雜程度和效率也就不能太大和太低。和上一個理由類似,MIME協議等用於傳送Email的協議解決的是如何收發Email,而並不 是如何安全的收發Email。因此演算法的複雜程度要小,效率要高,否則因為傳送Email而大量佔用資源,路就有點走歪了。
但是,如果是基於以上兩點,那麼我們使用最簡單的愷撒法即可,為什麼Base64看起來要比愷撒法複雜呢?這是因為在Email的傳送過程中,由於歷史原 因,Email只被允許傳送ASCII字元,即一個8位位元組的低7位。因此,如果您傳送了一封帶有非ASCII字元(即位元組的最高位是1)的Email通 過有“歷史問題”的閘道器時就可能會出現問題。閘道器可能會把最高位置為0!很明顯,問題就這樣產生了!因此,為了能夠正常的傳送Email,這個問題就必須 考慮!所以,單單靠改變字母的位置的愷撒之類的方案也就不行了。關於這一點可以參考RFC2046。
基於以上的一些主要原因產生了Base64編碼。
Base64編碼要求把3個8位位元組(38=24)轉化為4個6位的位元組(46=24),之後在6位的前面補兩個0,形成8位一個位元組的形式。
QP(Quote-Printable)
通常縮寫為“Q”方法,其原理是把一個 8 bit 的字元用兩個16進位制數值表示,然後在前面加“=”。所以我們看到經過QP編碼後的檔案通常是這個樣子:=B3=C2=BF=A1=C7=E5=A3=AC=C4=FA=BA=C3=A3=A1。
最後,我們希望你看了這篇文章之後不要混淆字符集和字元編碼的概念,還有對以上談到的各種編碼方式的原因有大致的瞭解,象utf-8這類是為了解析 unicode這種字符集而制定,而base64這類是為了解決實際的網路應用而制定。為了讓你便於記憶,對先前介紹的字符集進行統計和分類:
語言字符集正式名稱
英語、西歐語ASCII,ISO-8859-1MBCS 多位元組
簡體中文GB2312MBCS 多位元組
繁體中文BIG5MBCS 多位元組
簡繁中文GBKMBCS 多位元組
中文、日文及朝鮮語GB18030MBCS 多位元組
各國語言UNICODE,UCSDBCS 寬位元組
在這裡順便給大家推薦一個架構交流群:617434785,裡面會分享一些資深架構師錄製的視訊錄影:有Spring,MyBatis,Netty原始碼分析,高併發、高效能、分散式、微服務架構的原理,JVM效能優化這些成為架構師必備的知識體系。還能領取免費的學習資源。相信對於已經工作和遇到技術瓶頸的碼友,在這個群裡會有你需要的內容。