常見的字符編碼辨析

在說(shuō)常見的字符編碼(ASCII、gb2312、gbk、utf-8等)之前,我們先來(lái)看看編碼的歷史吧。

編碼編年史

  • 先是ASCII編碼,使用一個(gè)字節(jié)的7位來(lái)表示128個(gè)字符(大小寫字母,數(shù)字0到9、標(biāo)點(diǎn)符號(hào)、及在美式英語(yǔ)中使用的特殊控制字符);
  • 表示的字符實(shí)在太少,出現(xiàn)了EASCII,EASCII碼比ASCII碼擴(kuò)充出來(lái)的128符號(hào)包括表格符號(hào)、計(jì)算符號(hào)、希臘字母和特殊的拉丁符號(hào);
  • 太小家子氣了,中國(guó)使用兩個(gè)字節(jié)擴(kuò)充了ASCII,稱之為GB2312,支持漢字6763個(gè)和非漢字圖形字符682個(gè);
  • 罕用字和繁體字GB2312處理不過(guò)來(lái),GBK及GB 18030漢字字符集相繼出現(xiàn)以解決這個(gè)問(wèn)題;
  • ISO(國(guó)際標(biāo)準(zhǔn)化組織)看不下去了,制定了專為解決傳統(tǒng)的字符編碼方案的局限性的Unicode;
  • 為了節(jié)約傳輸消耗和存儲(chǔ)空間,UTF-8和UTF-16應(yīng)運(yùn)而生;
  • Base64主要是為了解決有些系統(tǒng)只能使用ASCII的尷尬,本身比較適合處理文本數(shù)據(jù)的傳輸和存儲(chǔ);

  • encodeUriComponent:它是將中文、韓文等特殊字符轉(zhuǎn)換成utf-8格式的url編碼。

ASCII編碼

ASCII(American Standard Code for Information Interchange,美國(guó)信息交換標(biāo)準(zhǔn)代碼)是基于拉丁字母的一套電腦編碼系統(tǒng)。它主要用于顯示現(xiàn)代英語(yǔ),而其擴(kuò)展版本EASCII則可以部分支持其他西歐語(yǔ)言,并等同于國(guó)際標(biāo)準(zhǔn)ISO/IEC 646。

ASCII第一次以規(guī)范標(biāo)準(zhǔn)的型態(tài)發(fā)表是在1967年,最后一次更新則是在1986年,至今為止共定義了128個(gè)字符;其中33個(gè)字符無(wú)法顯示(一些終端提供了擴(kuò)展,使得這些字符可顯示為諸如笑臉、撲克牌花式等8-bit符號(hào)),且這33個(gè)字符多數(shù)都已是陳廢的控制字符??刂谱址挠猛局饕怯脕?lái)操控已經(jīng)處理過(guò)的文字。在33個(gè)字符之外的是95個(gè)可顯示的字符,包含用鍵盤敲下空白鍵所產(chǎn)生的空白字符也算1個(gè)可顯示字符(顯示為空白)。

非ASCII編碼

英語(yǔ)用128個(gè)符號(hào)編碼就夠了,但是用來(lái)表示其他語(yǔ)言,128個(gè)符號(hào)是不夠的,所以就出現(xiàn)了很多非ASCII編碼。

GB 2312

定義

GB 2312 或 GB 2312–80 是中華人民共和國(guó)國(guó)家標(biāo)準(zhǔn)簡(jiǎn)體中文字符集,全稱《信息交換用漢字編碼字符集·基本集》,又稱GB0,由中國(guó)國(guó)家標(biāo)準(zhǔn)總局發(fā)布,1981年5月1日實(shí)施。GB 2312編碼通行于中國(guó)大陸;新加坡等地也采用此編碼。中國(guó)大陸幾乎所有的中文系統(tǒng)和國(guó)際化的軟件都支持GB 2312。

概述

GB 2312標(biāo)準(zhǔn)共收錄6763個(gè)漢字,其中一級(jí)漢字3755個(gè),二級(jí)漢字3008個(gè);同時(shí)收錄了包括拉丁字母、希臘字母、日文平假名及片假名字母、俄語(yǔ)西里爾字母在內(nèi)的682個(gè)字符。

GB 2312的出現(xiàn),基本滿足了漢字的計(jì)算機(jī)處理需要,它所收錄的漢字已經(jīng)覆蓋中國(guó)大陸99.75%的使用頻率。但對(duì)于人名、古漢語(yǔ)等方面出現(xiàn)的罕用字和繁體字,GB 2312不能處理,因此后來(lái)GBK及GB 18030漢字字符集相繼出現(xiàn)以解決這些問(wèn)題。

在使用GB 2312的程序通常采用EUC(EUC全名為Extended Unix Code,是一個(gè)使用8位編碼來(lái)表示字符的方法。)儲(chǔ)存方法,以便兼容于ASCII。瀏覽器編碼表上的“GB2312”,通常都是指“EUC-CN”表示法。

分區(qū)表示

GB 2312中對(duì)所收漢字進(jìn)行了“分區(qū)”處理,每區(qū)含有94個(gè)漢字/符號(hào)。這種表示方式也稱為區(qū)位碼。

01–09區(qū)為特殊符號(hào)。

16–55區(qū)為一級(jí)漢字,按拼音排序。

56–87區(qū)為二級(jí)漢字,按部首/筆畫排序。

舉例來(lái)說(shuō),“啊”字是GB 2312之中的第一個(gè)漢字,它的區(qū)位碼就是1601。

10–15區(qū)及88–94區(qū)則未有編碼。但在附錄3,則在第10區(qū)推薦作為 GB 1988–80 中的94個(gè)圖形字符區(qū)域(即第3區(qū)字符之半形版本)。

字節(jié)結(jié)構(gòu)

每個(gè)漢字及符號(hào)以兩個(gè)字節(jié)來(lái)表示。第一個(gè)字節(jié)稱為“高位字節(jié)”,第二個(gè)字節(jié)稱為“低位字節(jié)”。

“高位字節(jié)”使用了0xA1–0xF7(把01–87區(qū)的區(qū)號(hào)加上0xA0),“低位字節(jié)”使用了0xA1–0xFE(把01–94加上0xA0)。由于一級(jí)漢字從16區(qū)起始,漢字區(qū)的“高位字節(jié)”的范圍是0xB0–0xF7,“低位字節(jié)”的范圍是0xA1–0xFE,占用的碼位是72*94=6768。其中有5個(gè)空位是D7FA–D7FE。

例如“啊”字在大多數(shù)程序中,會(huì)以兩個(gè)字節(jié),0xB0(第一個(gè)字節(jié))0xA1(第二個(gè)字節(jié))儲(chǔ)存。(與區(qū)位碼對(duì)比:0xB0=0xA0+16,0xA1=0xA0+1)。

有兩種不同的GB 2312實(shí)現(xiàn)

有兩種不同的GB 2312實(shí)現(xiàn),在它們之間存在少量的差別,其中至少有一個(gè)是錯(cuò)誤的。

實(shí)現(xiàn)A與GBK/GB 18030兼容,實(shí)現(xiàn)B則不兼容。

gb2312的兩種實(shí)現(xiàn)

在2015年,微軟.Net Framework在使用實(shí)現(xiàn)A。 iconv-1.14, php-5.6, ActivePerl-5.20, Java 1.7, Python 3.4在使用實(shí)現(xiàn)B.[2] Ruby 2.2則同時(shí)兼容實(shí)現(xiàn)A和實(shí)現(xiàn)B,對(duì)這幾個(gè)有沖突的字符,它在內(nèi)部轉(zhuǎn)換為實(shí)現(xiàn)A。

GBK編碼

漢字內(nèi)碼擴(kuò)展規(guī)范,稱GBK,全名為《漢字內(nèi)碼擴(kuò)展規(guī)范(GBK)》1.0版,由中華人民共和國(guó)全國(guó)信息技術(shù)標(biāo)準(zhǔn)化技術(shù)委員會(huì)1995年12月1日制訂,國(guó)家技術(shù)監(jiān)督局標(biāo)準(zhǔn)化司和電子工業(yè)部科技與質(zhì)量監(jiān)督司1995年12月15日聯(lián)合以《技術(shù)標(biāo)函[1995]229號(hào)》文件的形式公布。

GBK的K為漢語(yǔ)拼音Kuo Zhan(擴(kuò)展)中“擴(kuò)”字的聲母。英文全稱Chinese Internal Code Extension Specification。

GBK 只為“技術(shù)規(guī)范指導(dǎo)性文件”,不屬于國(guó)家標(biāo)準(zhǔn)。國(guó)家質(zhì)量技術(shù)監(jiān)督局于2000年3月17日推出了GB 18030-2000標(biāo)準(zhǔn),以取代GBK。

Unicode編碼

unicode(中文:萬(wàn)國(guó)碼、國(guó)際碼、統(tǒng)一碼、單一碼)是計(jì)算機(jī)科學(xué)領(lǐng)域里的一項(xiàng)業(yè)界標(biāo)準(zhǔn)。它對(duì)世界上大部分的文字系統(tǒng)進(jìn)行了整理、編碼,使得電腦可以用更為簡(jiǎn)單的方式來(lái)呈現(xiàn)和處理文字。

Unicode伴隨著通用字符集的標(biāo)準(zhǔn)而發(fā)展,同時(shí)也以書本的形式[1]對(duì)外發(fā)表。Unicode至今仍在不斷增修,每個(gè)新版本都加入更多新的字符。目前最新的版本為2016年6月21日公布的9.0.0[2],已經(jīng)收入超過(guò)十萬(wàn)個(gè)字符(第十萬(wàn)個(gè)字符在2005年獲采納)。Unicode涵蓋的數(shù)據(jù)除了視覺上的字形、編碼方法、標(biāo)準(zhǔn)的字符編碼外,還包含了字符特性,如大小寫字母。

Unicode發(fā)展由非營(yíng)利機(jī)構(gòu)統(tǒng)一碼聯(lián)盟負(fù)責(zé),該機(jī)構(gòu)致力于讓Unicode方案替換既有的字符編碼方案。因?yàn)榧扔械姆桨竿臻g非常有限,亦不適用于多語(yǔ)環(huán)境。

Unicode備受認(rèn)可,并廣泛地應(yīng)用于電腦軟件的國(guó)際化與本地化過(guò)程。有很多新科技,如可擴(kuò)展置標(biāo)語(yǔ)言、Java編程語(yǔ)言以及現(xiàn)代的操作系統(tǒng),都采用Unicode編碼。

需要注意的是,Unicode只是一個(gè)符號(hào)集,它只規(guī)定了符號(hào)的二進(jìn)制代碼,卻沒(méi)有規(guī)定這個(gè)二進(jìn)制代碼應(yīng)該如何存儲(chǔ)。

比如,漢字“嚴(yán)”的unicode是十六進(jìn)制數(shù)4E25,轉(zhuǎn)換成二進(jìn)制數(shù)足足有15位(100111000100101),也就是說(shuō)這個(gè)符號(hào)的表示至少需要2個(gè)字節(jié)。表示其他更大的符號(hào),可能需要3個(gè)字節(jié)或者4個(gè)字節(jié),甚至更多。

這里就有兩個(gè)嚴(yán)重的問(wèn)題,第一個(gè)問(wèn)題是,如何才能區(qū)別unicode和ascii?計(jì)算機(jī)怎么知道三個(gè)字節(jié)表示一個(gè)符號(hào),而不是分別表示三個(gè)符號(hào)呢?第二個(gè)問(wèn)題是,我們已經(jīng)知道,英文字母只用一個(gè)字節(jié)表示就夠了,如果unicode統(tǒng)一規(guī)定,每個(gè)符號(hào)用三個(gè)或四個(gè)字節(jié)表示,那么每個(gè)英文字母前都必然有二到三個(gè)字節(jié)是0,這對(duì)于存儲(chǔ)來(lái)說(shuō)是極大的浪費(fèi),文本文件的大小會(huì)因此大出二三倍,這是無(wú)法接受的。

它們?cè)斐傻慕Y(jié)果是:1)出現(xiàn)了unicode的多種存儲(chǔ)方式,也就是說(shuō)有許多種不同的二進(jìn)制格式,可以用來(lái)表示unicode。2)unicode在很長(zhǎng)一段時(shí)間內(nèi)無(wú)法推廣,直到互聯(lián)網(wǎng)的出現(xiàn)。

Unicode的實(shí)現(xiàn)方式

Unicode的實(shí)現(xiàn)方式不同于編碼方式。一個(gè)字符的Unicode編碼是確定的。但是在實(shí)際傳輸過(guò)程中,由于不同系統(tǒng)平臺(tái)的設(shè)計(jì)不一定一致,以及出于節(jié)省空間的目的,對(duì)Unicode編碼的實(shí)現(xiàn)方式有所不同。Unicode的實(shí)現(xiàn)方式稱為Unicode轉(zhuǎn)換格式(Unicode Transformation Format,簡(jiǎn)稱為UTF)。

UTF-8

互聯(lián)網(wǎng)的普及,強(qiáng)烈要求出現(xiàn)一種統(tǒng)一的編碼方式。UTF-8就是在互聯(lián)網(wǎng)上使用最廣的一種unicode的實(shí)現(xiàn)方式。其他實(shí)現(xiàn)方式還包括UTF-16和UTF-32,不過(guò)在互聯(lián)網(wǎng)上基本不用。重復(fù)一遍,這里的關(guān)系是,UTF-8是Unicode的實(shí)現(xiàn)方式之一。

UTF-8最大的一個(gè)特點(diǎn),就是它是一種變長(zhǎng)的編碼方式。它可以使用1~4個(gè)字節(jié)表示一個(gè)符號(hào),根據(jù)不同的符號(hào)而變化字節(jié)長(zhǎng)度。

UTF-8的編碼規(guī)則很簡(jiǎn)單,只有二條:

1)對(duì)于單字節(jié)的符號(hào),字節(jié)的第一位設(shè)為0,后面7位為這個(gè)符號(hào)的unicode碼。因此對(duì)于英語(yǔ)字母,UTF-8編碼和ASCII碼是相同的。

2)對(duì)于n字節(jié)的符號(hào)(n>1),第一個(gè)字節(jié)的前n位都設(shè)為1,第n+1位設(shè)為0,后面字節(jié)的前兩位一律設(shè)為10。剩下的沒(méi)有提及的二進(jìn)制位,全部為這個(gè)符號(hào)的unicode碼。

下表總結(jié)了編碼規(guī)則,字母x表示可用編碼的位。

utf-8碼表

Unicode 和 UTF-8 之間的轉(zhuǎn)換關(guān)系表 ( x 字符表示碼點(diǎn)占據(jù)的位 )

UTF-16

UTF-16是Unicode字符編碼五層次模型的第三層:字符編碼表(Character Encoding Form,也稱為 "storage format")的一種實(shí)現(xiàn)方式。即把Unicode字符集的抽象碼位映射為16位長(zhǎng)的整數(shù)(即碼元)的序列,用于數(shù)據(jù)存儲(chǔ)或傳遞。Unicode字符的碼位,需要1個(gè)或者2個(gè)16位長(zhǎng)的碼元來(lái)表示,因此這是一個(gè)變長(zhǎng)表示。

UTF-16比起UTF-8,好處在于大部分字符都以固定長(zhǎng)度的字節(jié) (2字節(jié)) 儲(chǔ)存,但UTF-16卻無(wú)法兼容于ASCII編碼。

UTF-32

UTF-32 (或 UCS-4)是一種將Unicode字符編碼的協(xié)議,對(duì)每一個(gè)Unicode碼位使用恰好32比特。UTF 只有此一種定長(zhǎng)編碼。

UTF-32 使用32-比特的碼值,只在0到10FFFF的字碼空間(百萬(wàn)個(gè)碼位)。

UTF-32 原本是一個(gè) UCS-4 的子集,于是就現(xiàn)狀而言,除了 UTF-32 標(biāo)準(zhǔn)包含額外的 Unicode 意涵,UCS-4 和 UTF-32 大體是相同的。

小端和大端問(wèn)題

Little endian和Big endian

上一節(jié)已經(jīng)提到,Unicode碼可以采用UCS-2格式直接存儲(chǔ)。以漢字”嚴(yán)“為例,Unicode碼是4E25,需要用兩個(gè)字節(jié)存儲(chǔ),一個(gè)字節(jié)是4E,另一個(gè)字節(jié)是25。存儲(chǔ)的時(shí)候,4E在前,25在后,就是Big endian方式;25在前,4E在后,就是Little endian方式。

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

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

那么很自然的,就會(huì)出現(xiàn)一個(gè)問(wèn)題:計(jì)算機(jī)怎么知道某一個(gè)文件到底采用哪一種方式編碼?

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

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

Base64

Base64是一種基于64個(gè)可打印字符來(lái)表示二進(jìn)制數(shù)據(jù)的表示方法。由于2的6次方等于64,所以每6個(gè)比特為一個(gè)單元,對(duì)應(yīng)某個(gè)可打印字符。三個(gè)字節(jié)有24個(gè)比特,對(duì)應(yīng)于4個(gè)Base64單元,即3個(gè)字節(jié)需要用4個(gè)可打印字符來(lái)表示。

在Base64中的可打印字符包括字母A-Z、a-z、數(shù)字0-9,這樣共有62個(gè)字符,此外兩個(gè)可打印符號(hào)在不同的系統(tǒng)中而不同。

完整的base64定義可見RFC 1421和RFC 2045。編碼后的數(shù)據(jù)比原始數(shù)據(jù)略長(zhǎng),為原來(lái)的4/3。

轉(zhuǎn)換過(guò)程:

轉(zhuǎn)換的時(shí)候,將三個(gè)byte的數(shù)據(jù),先后放入一個(gè)24bit的緩沖區(qū)中,先來(lái)的byte占高位。數(shù)據(jù)不足3byte的話,于緩沖器中剩下的bit用0補(bǔ)足。然后,每次取出6(因?yàn)?6=64)個(gè)bit,按照其值選擇ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/中的字符作為編碼后的輸出。不斷進(jìn)行,直到全部輸入數(shù)據(jù)轉(zhuǎn)換完成。

當(dāng)原數(shù)據(jù)長(zhǎng)度不是3的整數(shù)倍時(shí), 如果最后剩下一個(gè)輸入數(shù)據(jù),在編碼結(jié)果后加2個(gè)“=”;如果最后剩下兩個(gè)輸入數(shù)據(jù),編碼結(jié)果后加1個(gè)“=”;如果沒(méi)有剩下任何數(shù)據(jù),就什么都不要加,這樣才可以保證數(shù)據(jù)還原的正確性。(如果要編碼的字節(jié)數(shù)不能被3整除,最后會(huì)多出1個(gè)或2個(gè)字節(jié),那么可以使用下面的方法進(jìn)行處理:先使用0字節(jié)值在末尾補(bǔ)足,使其能夠被3整除,然后再進(jìn)行base64的編碼。在編碼后的base64文本后加上一個(gè)或兩個(gè)'='號(hào),代表補(bǔ)足的字節(jié)數(shù)。也就是說(shuō),當(dāng)最后剩余一個(gè)八位字節(jié)(一個(gè)byte)時(shí),最后一個(gè)6位的base64字節(jié)塊有四位是0值,最后附加上兩個(gè)等號(hào);如果最后剩余兩個(gè)八位字節(jié)(2個(gè)byte)時(shí),最后一個(gè)6位的base字節(jié)塊有兩位是0值,最后附加一個(gè)等號(hào)。參考下表:)

Base64編碼的作用

由于某些系統(tǒng)中只能使用ASCII字符。Base64就是用來(lái)將非ASCII字符的數(shù)據(jù)轉(zhuǎn)換成ASCII字符的一種方法。它使用下面表中所使用的字符與編碼。

比如:GB2312-根據(jù)Base64規(guī)則->轉(zhuǎn)換成ASCII碼,

接收端收到ASCII碼-根據(jù)Base64規(guī)則->還原到GB2312

Base64常用于在通常處理文本數(shù)據(jù)的場(chǎng)合,表示、傳輸、存儲(chǔ)一些二進(jìn)制數(shù)據(jù)。包括MIME的email、在XML中存儲(chǔ)復(fù)雜數(shù)據(jù)。而且base64特別適合在http,mime協(xié)議下快速傳輸數(shù)據(jù)。

總結(jié)

關(guān)于編碼和解碼一定要對(duì)應(yīng),否則會(huì)產(chǎn)生亂碼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 原文在這里:各種字符集和編碼詳解 在軟件的編碼和實(shí)現(xiàn)中,我們可能會(huì)碰到個(gè) 一個(gè)比較頭疼的問(wèn)題--編碼,不同字符間的...
    舌尖上的大胖閱讀 1,978評(píng)論 0 2
  • 字符集和編碼簡(jiǎn)介 在編程中常??梢砸姷礁鞣N字符集和編碼,包括ASCII,MBCS,Unicode等字符集。確切的說(shuō)...
    蘭山小亭閱讀 9,074評(píng)論 0 13
  • 刷了一天,韓網(wǎng)、貼吧、微博,撕的不可開交,都是為了那個(gè)讓人從胸腔疼到肋骨的男孩啊。也許是94里的七封黨傷怕了...
    Lyrashi閱讀 645評(píng)論 0 1
  • 看了一篇文章,說(shuō)《一個(gè)人靠不靠譜,就看這三件小事》,文中提到: 我所理解的“靠譜”就是你把這事交給他之后完全不用操...
    愛中醫(yī)超塵閱讀 195評(píng)論 0 0

友情鏈接更多精彩內(nèi)容