最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

史詩(shī)級(jí)計(jì)算機(jī)字符編碼知識(shí)分享,萬(wàn)字長(zhǎng)文,一文即懂!

2023-05-11 12:10 作者:nickkckckck  | 我要投稿

本文由阿里技術(shù)團(tuán)隊(duì)詹向陽(yáng)(驍飏)分享,原題“一文讀懂字符編碼”,有修訂和改動(dòng)。

一、引言

說(shuō)起計(jì)算機(jī)字符編碼,讓我想起了科幻巨作《三體-黑暗深林》人類遇到外星文明魔戒的畫面(以下內(nèi)容摘自大劉的原文)。

人類第一次近距離看到四維物體魔戒,卓文用中頻電波發(fā)送了一個(gè)問候語(yǔ)。這是一幅簡(jiǎn)單的點(diǎn)陣圖,圖中由六行不同數(shù)量的點(diǎn)組成了一個(gè)質(zhì)數(shù)數(shù)列:1,3,5,7,11,13。

他們沒有指望得到應(yīng)答,但應(yīng)答立刻出現(xiàn)了

.....

太空艇收到了來(lái)自“魔戒”的一系列點(diǎn)陣圖,第一幅是很整齊的一個(gè)8×8點(diǎn)陣,共六十四個(gè)點(diǎn);第二幅圖中點(diǎn)陣的一角少了一個(gè)點(diǎn),剩下六十三個(gè);第三幅圖中又少一點(diǎn),剩六十二個(gè)……“這是倒計(jì)數(shù),也相當(dāng)于一個(gè)進(jìn)度條,可能表示‘它’已經(jīng)收到了羅塞塔,正在譯解,讓我們等侍?!表f斯特說(shuō)。

“可為什么是六十四點(diǎn)呢?”

“使用二進(jìn)制時(shí)一個(gè)不大不小的數(shù)唄,與十進(jìn)制的一百差不多?!?/p>

卓文和關(guān)一帆都很慶幸能帶韋斯特來(lái),在與未知的智慧體建立交流方面、心理學(xué)家確實(shí)很有才能。

在倒計(jì)數(shù)達(dá)到五十七時(shí),令人激動(dòng)的事情出現(xiàn)了:下一個(gè)計(jì)數(shù)沒有用點(diǎn)陣表示,“魔戒”發(fā)來(lái)的圖片上赫然顯示出人類的阿拉伯?dāng)?shù)字56!

.....

在人類探索外星文明、邁向星辰大海的宇宙征程里,也離不開這種最最基礎(chǔ)的編碼問題。

前一陣跟同事碰到了字符亂碼的問題,了解后發(fā)現(xiàn)這個(gè)問題存在兩年了,我們程序員每天都在跟編碼打交道,但大家對(duì)字符編碼都是一知半解:“天天吃豬肉卻很少見過豬跑”,今天我就把它徹底講透!

* 推薦閱讀:如果本文太“硬”,就看看這兩篇吧:《史上最通俗,徹底搞懂字符亂碼問題的本質(zhì)》、《字符編碼那點(diǎn)事:快速理解ASCII、Unicode、GBK和UTF-8》。

技術(shù)交流:

- 移動(dòng)端IM開發(fā)入門文章:《新手入門一篇就夠:從零開發(fā)移動(dòng)端IM》

- 開源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK(備用地址點(diǎn)此)

(本文已同步發(fā)布于:http://www.52im.net/thread-4210-1-1.html)

二、什么是字符編碼?

我們知道計(jì)算機(jī)的世界只有0和1,如果沒有字符編碼,我們看到的就是一串"110010100101100111001....",我們的溝通就好像是在對(duì)牛彈琴,我看不懂它,它看不懂我。

字符編碼就好比人類和機(jī)器之間的翻譯程序,把我們熟知的字符文字翻譯成機(jī)器能讀懂的二進(jìn)制,同時(shí)把二進(jìn)制翻譯成我們能看懂的字符。

以下是百科對(duì)字符編碼的解釋:

字符編碼(Character encoding)也稱字集碼,是把字符集中的字符,編碼為指定集合中的某一對(duì)象(例如:比特模式、自然數(shù)序列、8位組或者電脈沖),以便文本在計(jì)算機(jī)中存儲(chǔ)或者通信網(wǎng)絡(luò)的傳遞。常見的例子是將拉丁字母表編碼成摩斯電碼和ASCII,比如ASCII編碼是將字母、數(shù)字和其它符號(hào)進(jìn)行編號(hào),并用7比特的二進(jìn)制來(lái)表示這個(gè)整數(shù)。

字符集(Character set)是多個(gè)字符的集合,字符集種類較多,每個(gè)字符集包含的字符個(gè)數(shù)不同,常見字符集名稱:ASCII字符集、GB2312字符集、BIG5字符集、 GB18030字符集、Unicode字符集等。計(jì)算機(jī)要準(zhǔn)確的處理各種字符集文字,就需要進(jìn)行字符編碼,以便計(jì)算機(jī)能夠識(shí)別和存儲(chǔ)各種文字。

三、為什么計(jì)算機(jī)需要編碼?

3.1、概述

編碼(Encode)是信息從一種形式轉(zhuǎn)換為另一種形式的過程,比如用預(yù)先規(guī)定的方法將字符(文字、數(shù)字、符號(hào)等)、圖像、聲音或其它對(duì)象轉(zhuǎn)換成規(guī)定的電脈沖信號(hào)或二進(jìn)制數(shù)字。

我們現(xiàn)在看到的一幅幅圖畫,聽到的一首首音樂,甚至我們寫的一行行代碼,敲下的一個(gè)個(gè)字符,所看到的所聽到的都是那么的真實(shí),但其實(shí)在背后都是一串“01”的數(shù)字。你昨天在手機(jī)上看到的那個(gè)心動(dòng)女孩,真實(shí)世界中并不存在,只是計(jì)算機(jī)用“01”數(shù)字幫你生成的“骷髏”而已(宅男夢(mèng)碎。。。)。

3.2、二進(jìn)制其實(shí)不存在

你可能認(rèn)為計(jì)算機(jī)中的數(shù)據(jù)就是“01”二進(jìn)制,但是實(shí)際上計(jì)算機(jī)中并沒有二進(jìn)制,即便我們知道所有的內(nèi)容都是存儲(chǔ)在硬盤中,但是你把它拆開可找不到里面有任何“0101”的數(shù)字,里面也只有盤片、磁道。就算我們放大了去看盤片,也只有凹凸不平的盤面,凸起的地方是被磁化過的,凹進(jìn)去的地方是沒有被磁化的;只是我們給凸起的地方取了個(gè)名字叫數(shù)字“1”,凹進(jìn)的地方取名叫數(shù)字“0”。

同樣內(nèi)存里你也找不到二進(jìn)制數(shù)字:內(nèi)存放大了看就是一堆電容組,內(nèi)存單元存儲(chǔ)的是“0”還是“1”取決于電容是否有電荷,有電荷我們認(rèn)為他是“1”,無(wú)電荷認(rèn)為他是“0”。但是電容是會(huì)放電的,時(shí)間一長(zhǎng),代表“1”的電容會(huì)放電,代表“0”的電容會(huì)吸電,這也是我們內(nèi)存不能斷電的原因,需要定期對(duì)電容進(jìn)行充電,保證“1”的電容電量有電。

再說(shuō)顯示器:這個(gè)大家感受是最直接的,你透過顯示器看到的美女畫皮、日月山川,其實(shí)就是一個(gè)個(gè)不同顏色的發(fā)光二極管發(fā)出強(qiáng)弱不一的光點(diǎn),顯示器就是一群發(fā)光二極管組成的矩陣,其中每一個(gè)二極管可以被稱為一個(gè)像素,“1”表示亮,“0”表示滅,而我們平時(shí)能看到五彩的顏色,是把三種顏色(紅綠藍(lán)三原色)的發(fā)光二極管做到了一起。那對(duì)于一個(gè)ASCII編碼“65”最后又怎么顯示成“A”的呢?這就是顯卡的功勞,顯卡中存儲(chǔ)了每一個(gè)字符的圖形數(shù)據(jù)(也稱字形碼),將二維矩陣的圖形數(shù)據(jù)傳給顯示器成像(如下圖所示)。

因此:所謂的0和1都是電流脈沖信號(hào),二進(jìn)制其實(shí)是我們抽象出來(lái)的數(shù)學(xué)邏輯概念。那我們?yōu)槭裁匆枚M(jìn)制表示?

因?yàn)椋?/strong>二進(jìn)制只有兩種狀態(tài),使用有兩個(gè)穩(wěn)定狀態(tài)的物理器件就可以表示二進(jìn)制中的每一位,例如用高低電平或電荷的正負(fù)性、燈的亮和滅都可以很方便地用“0”和“1”來(lái)表示,這為計(jì)算機(jī)實(shí)現(xiàn)邏輯運(yùn)算和邏輯判斷提供了便利條件。

四、計(jì)算機(jī)編碼轉(zhuǎn)換過程

4.1、概述

正因?yàn)橛?jì)算機(jī)只能表示“01”的邏輯概念,無(wú)法直接表示圖片以及文字,所以我們需要一定的轉(zhuǎn)換過程。

這其實(shí)就是我們按照一定的規(guī)則維護(hù)了字符-數(shù)字的映射關(guān)系,比如我們把“A”抽象成計(jì)算機(jī)中的“1”,當(dāng)我們看到1的時(shí)候就認(rèn)為這是“A”,本質(zhì)上就是一張映射表,理論上你可以隨意給每個(gè)字符分配一個(gè)獨(dú)一無(wú)二的編號(hào)(character code,字符編碼)。

比如下表這樣:

接下來(lái)我們來(lái)看下一個(gè)文字從“輸入-轉(zhuǎn)碼存儲(chǔ)-輸出(顯示/打?。钡暮?jiǎn)單流程。

首先:我們知道計(jì)算機(jī)是美國(guó)人發(fā)明的,規(guī)則是美國(guó)人定的,鍵盤上的按鍵也都是英文字母,所以編號(hào)不是你想怎么分配就怎么分配。對(duì)于英文字母的輸入,鍵盤和ASCII碼之間是直接對(duì)應(yīng)的,鍵盤按鍵“A”對(duì)應(yīng)的編號(hào)“65”,存儲(chǔ)到磁盤上也是“65”的二進(jìn)制直譯“01000001”,這很好理解。

但是:對(duì)于漢字輸入就不是這么回事了,鍵盤上可沒有漢字對(duì)應(yīng)的輸入按鍵,我們不可能直接敲出漢字字符。于是就有了輸入碼、機(jī)內(nèi)碼、字形碼的轉(zhuǎn)換關(guān)系,輸入碼幫助我們把英文鍵盤按鍵轉(zhuǎn)換成漢字字符,機(jī)內(nèi)碼幫助我們把漢字字符轉(zhuǎn)換成二進(jìn)制序列,字形碼幫助我們把二進(jìn)制序列輸出到顯示器成像。

4.2、輸入碼

我們模擬下漢字的輸入過程。

首先:打開txt文本敲下“nihao”的拼音字母,然后輸入欄會(huì)彈出多個(gè)符合條件的漢字詞組,最后我們會(huì)選擇相應(yīng)的編號(hào),就能實(shí)現(xiàn)漢字的輸入。

那這過程又是如何實(shí)現(xiàn)的呢?

計(jì)算機(jī)領(lǐng)域有一句如同摩西十誡般的神圣哲言:“計(jì)算機(jī)科學(xué)領(lǐng)域的任何問題都可以通過增加一個(gè)間接的中間層來(lái)解決”。

這里我們?cè)偌右粚影存I字母組合和漢字的映射表,好比英漢字典,這層我們稱為輸入碼,輸入碼到內(nèi)碼的過程就是一次查表轉(zhuǎn)換操作,比如“nihao”這幾個(gè)ASCII字符,大家可以隨便修改映射表以及候選編號(hào),我可以把他映射成“你好驍飏”(如下圖所示)。

4.3、機(jī)內(nèi)碼

機(jī)內(nèi)碼也稱內(nèi)碼,是字符編碼最核心的部分。

機(jī)內(nèi)碼是字符集在計(jì)算機(jī)中實(shí)際存儲(chǔ)、交換、通信使用的二進(jìn)制編碼,通過內(nèi)碼我們可以達(dá)到高效率的存儲(chǔ)、傳輸文本的目的。我們的外碼(輸入碼)實(shí)現(xiàn)了鍵盤按鍵和字符的映射轉(zhuǎn)換,但是機(jī)內(nèi)碼是讓字符真正變成了機(jī)器能讀懂的二進(jìn)制語(yǔ)言。

4.4、字形碼

計(jì)算機(jī)中的字符都是以內(nèi)碼的二進(jìn)制形式表示,我們?cè)趺窗褦?shù)字對(duì)應(yīng)的字符在顯示器上顯示出來(lái)呢,比如數(shù)字“1”代表漢字“你”,怎么把“1”顯示成“你”?

這就需要依賴字形碼,字形碼本質(zhì)上是一個(gè)n*n?的像素點(diǎn)陣,把某些位置的像素設(shè)置為白色(用 1 表示),其它位置像素設(shè)置為黑色(用 0 表示),每一個(gè)字符的字形都是預(yù)先存放在計(jì)算機(jī)內(nèi),而這樣的字形信息庫(kù)我們稱為字庫(kù)。

比如中文“你”的點(diǎn)陣圖,這樣一個(gè)?16*16?的像素矩陣,需要?16 * 16 / 8 = 32?字節(jié)的空間來(lái)表示,右邊的字模信息稱為字形碼。不同的字庫(kù)(如宋體、黑體)對(duì)同一個(gè)字符的字形編碼是不同的。

所以字符編碼到顯示的字形碼,其實(shí)又是另一張查找表,也就是字符編碼-字形碼的映射關(guān)系表。

其實(shí)我們也可以認(rèn)為字符編碼是字形碼的一種壓縮方式,一個(gè)占32字節(jié)的像素點(diǎn)陣壓縮成了2字節(jié)的機(jī)內(nèi)碼。

五、字符編碼的歷史

5.1、電報(bào)編碼

從廣義上來(lái)說(shuō),編碼的歷史很悠久,一直可以追溯到結(jié)繩記事的遠(yuǎn)古時(shí)期,但跟現(xiàn)代字符編碼比較接近的還是摩爾斯電碼的發(fā)明,自此開啟了信息通信時(shí)代的大門。

摩爾斯電碼是由美國(guó)人摩爾斯在1837年發(fā)明的,比起ASCII還要早100多年,在早期的無(wú)線電上作用非常大,它是每個(gè)無(wú)線電通訊者需必知的,它的是由點(diǎn)dot “.” 和劃dash “-” 這兩種符號(hào)所組成的,電報(bào)中表達(dá)為短滴和長(zhǎng)嗒,跟二進(jìn)制一樣也是二元碼。

一個(gè)二元肯定不夠表示我們的字母,那么就用多個(gè)二元來(lái)表示,比如嘀嗒“.-”代表字母“A”,嗒嘀嘀嘀“-...”代表字母“B”。

摩爾斯電碼表:

5.2、編碼紀(jì)元

計(jì)算機(jī)一開始發(fā)明出來(lái)時(shí)是用來(lái)解決數(shù)學(xué)計(jì)算問題的,后來(lái)人們發(fā)現(xiàn),計(jì)算機(jī)還可以做更多的事,例如文本處理等。那個(gè)時(shí)候的機(jī)器都很大,機(jī)器之間都是隔離的,沒考慮過機(jī)器的通信問題,各大廠商也各干各個(gè)的,搞自己的硬件搞自己的軟件,想怎么編碼就怎么編碼。

后來(lái)機(jī)器間需要相互通信的時(shí)候,發(fā)現(xiàn)在不同計(jì)算機(jī)上顯示出來(lái)的字符不一樣,在IBM上“00010100”數(shù)字代表“A”,跑到微軟系統(tǒng)上顯示成了“B”,大家就傻眼了。于是美國(guó)的標(biāo)準(zhǔn)化組織就跑出來(lái)制定了ASCII編碼(American Standard Code for Information Interchange),統(tǒng)一了游戲規(guī)則,規(guī)定了常用符號(hào)用哪些二進(jìn)制數(shù)來(lái)表示。

5.3、百花齊放

統(tǒng)一ASCII 碼標(biāo)準(zhǔn)對(duì)于英語(yǔ)國(guó)家很開心,但是ASCII編碼只考慮了英文字母,后來(lái)計(jì)算機(jī)傳到歐洲地區(qū),法國(guó)人需要加個(gè)字母符號(hào)(如:é),德國(guó)人又需要加幾個(gè)字母(? ?、? ?、ü ü、?),幸好ASCII只用了前127個(gè)編號(hào),于是歐洲人就將ASCII沒用完的編碼(128-255)為自己特有的符號(hào)編碼,也能很好的一起玩耍。

但是等傳到我們中國(guó)后,做為博大精深的漢語(yǔ)言就徹底蒙圈了,我們有幾萬(wàn)個(gè)漢字,255個(gè)編號(hào)完全不夠用啊,所以有了后來(lái)的多字節(jié)編碼… 因此,各個(gè)國(guó)家都推出了本國(guó)語(yǔ)言的編碼表,也就有了后來(lái)的 ISO 8859 系列、GB系列(GB2312、GBK、GB18030、GB13000)、Big5、EUC-KR、JIS … ,不過為了能在計(jì)算機(jī)系統(tǒng)中通用,這些擴(kuò)展的編碼均直接或間接兼容 ASCII 碼。

而微軟/IBM這些國(guó)際化產(chǎn)商為了把自己的產(chǎn)品賣到全世界,就需要支持各個(gè)國(guó)家的語(yǔ)言,要在不同的地方采用當(dāng)?shù)氐木幋a方式,于是他們就把全世界的編碼方式都集中到一起并編上號(hào),并且起了個(gè)名字叫代碼頁(yè)(Codepage,又稱內(nèi)碼表),所以我們有時(shí)候也會(huì)看到xx代碼頁(yè)來(lái)指代某種字符編碼,比如在微軟系統(tǒng)里 中文GBK編碼對(duì)應(yīng)的是936代碼頁(yè),繁體中文 Big5編碼對(duì)應(yīng)的是950代碼頁(yè)。

這些既兼容ASCII又互相之間不兼容的字符編碼,后來(lái)又統(tǒng)稱為ANSI編碼。看到下面這張圖估計(jì)大家就很熟悉了,window下面我們基本上都用ANSI編碼保存。

ANSI的字面意思并非指字符編碼,而是美國(guó)的一個(gè)非營(yíng)利組織,是美國(guó)國(guó)家標(biāo)準(zhǔn)學(xué)會(huì)(American National Standards Institute)的縮寫,ANSI這個(gè)組織為字符編碼做了很多標(biāo)準(zhǔn)制定工作,后來(lái)大家習(xí)慣把這類混亂的多字節(jié)編碼叫ANSI編碼或者標(biāo)準(zhǔn)代碼頁(yè)。

ANSI編碼只是一個(gè)范稱,一般代表系統(tǒng)默認(rèn)的編碼方式,而且并不是確定的某一種編碼方式——比如在Window操作系統(tǒng)里,中國(guó)區(qū)ANSI編碼指的是GB編碼,在香港地區(qū)ANSI編碼指的是Big5編碼,在韓國(guó)ANSI編碼指的是EUC-KR編碼。

5.4、天下一統(tǒng)

由于各個(gè)國(guó)家各搞各的字符編碼,如果有些人想裝逼中文里飚兩句韓文怎么辦呢?不好意思,你的逼級(jí)太高,沒法支持,你選擇了GB2312就只能打出中文字符。同時(shí)各大國(guó)際廠商在兼容各種字符編碼問題上也深受折磨,于是忍無(wú)可忍之下,決定開發(fā)一套能容納全世界所有字符的編碼,就有了后面大名鼎鼎的Unicode。

Unicode也叫萬(wàn)國(guó)碼,包括字符集、編碼方案等。

Unicode是為了解決傳統(tǒng)的字符編碼方案的局限而產(chǎn)生的,它為每種語(yǔ)言中的每個(gè)字符設(shè)定了統(tǒng)一并且唯一的二進(jìn)制編碼,在這種語(yǔ)言環(huán)境下,不會(huì)再有語(yǔ)言的編碼沖突,在同屏下也可以顯示任何國(guó)家語(yǔ)言的內(nèi)容,這就是Unicode的最大好處。

在Unicode編碼方案里常見的有四種編碼實(shí)現(xiàn)方案UTF-7、 UTF-8、UTF-16、UTF-32,最為知名的就是 UTF-8。Unicode設(shè)計(jì)之初是采用雙字節(jié)定長(zhǎng)編碼的UTF-16,但是發(fā)現(xiàn)歷史包袱太重推不動(dòng),最后出了個(gè)變長(zhǎng)的UTF-8才被廣泛接受。

六、字符編碼模型

6.1、傳統(tǒng)編碼模型

在傳統(tǒng)字符編碼模型中,基本上都是將字符集里的字符用十進(jìn)制進(jìn)行逐一的編號(hào),然后把十進(jìn)制編號(hào)直接轉(zhuǎn)成對(duì)應(yīng)的二進(jìn)制碼,可以說(shuō)該字符編號(hào)就是字符的編碼。

計(jì)算機(jī)在處理字符與數(shù)字的轉(zhuǎn)換關(guān)系上其實(shí)就是查找映射表的過程。

像ASCII編碼就是給每個(gè)英文字符編一個(gè)獨(dú)一無(wú)二的數(shù)字,整個(gè)編碼處理過程相對(duì)還是比較簡(jiǎn)單的,計(jì)算機(jī)內(nèi)部直接就映射成了二進(jìn)制,十進(jìn)制的編號(hào)只是方便我們看的。

6.2、現(xiàn)代編碼模型

Unicode編碼模型采用了一個(gè)全新的編碼思路,將編碼模型劃分為4 個(gè)層次(也有說(shuō)5個(gè)層次的),不過第五層是傳輸層的編碼適配,放在編碼模型里嚴(yán)格來(lái)說(shuō)不是很恰當(dāng)。

這 4 個(gè)層次分別是:

  • 1)第一層,抽象字符集 ACR(Abstract Character Repertoire):定義抽象字符集合,明確各個(gè)抽象字符;

  • 2)第二層,編號(hào)字符集 CCS(Coded Character Set):將抽象字符集進(jìn)行數(shù)字編號(hào);

  • 3)第三層,字符編碼方式 CEF(Character Encoding Form):將字符編號(hào)編碼為邏輯上的碼元序列;

  • 4)第四層,字符編碼方案 CES(Character Encoding Scheme):將邏輯上的碼元序列編碼為物理字節(jié)序列。

下面將分別來(lái)詳細(xì)講講各層。

6.3、第一層:抽象字符集 ACR

所謂抽象字符集,就是抽象字符的合集。

它是一個(gè)無(wú)序集合,這里強(qiáng)調(diào)了字符是抽象的,也就是不僅包括我們視覺上能看到的狹義字符,比如“a”這樣的有形字符,也包括一些我們看不到的無(wú)形字符,比如一些控制字符“DELETE”、“NULL”等。

抽象的另一層含義是有些字形是由多個(gè)字符組合成的,比如西班牙語(yǔ)的 “?” 由“n”和“~”兩個(gè)字符組成,這一點(diǎn)上 Unicode 和傳統(tǒng)編碼標(biāo)準(zhǔn)不同,傳統(tǒng)編碼標(biāo)準(zhǔn)多是將 ? 視作一個(gè)獨(dú)立的字符,而 Unicode 中將其視為兩個(gè)字符的組合。

同時(shí)一個(gè)字符也可能會(huì)有多種視覺上的字形表示,比如一個(gè)漢字有楷、行、草、隸等多種形體,這些都視為同一個(gè)抽象字符(即字符集編碼是對(duì)字符而非字形編碼),如何顯示是字形庫(kù)的事。

漢字“人”的不同形態(tài):

抽象字符集有開放與封閉之分:開放的字符集指還會(huì)不斷新增字符的字符集,封閉字符集是指不會(huì)新增字符的字符集。比如ASCII就是封閉式的,只有128個(gè)字符,以后也不會(huì)再加,但是Unicode是開放式的,會(huì)不斷往里加新字符的,已經(jīng)從最初的 7163 個(gè)增加到現(xiàn)在的144,697 個(gè)字符。

6.4、第二層:編號(hào)字符集 CCS

編號(hào)字符集就是對(duì)抽象字符集里的每個(gè)字符進(jìn)行編號(hào),映射到一個(gè)非負(fù)整數(shù)的集合

編號(hào)一般用方便人類閱讀的十進(jìn)制、十六進(jìn)制來(lái)表示,比如“A”字符編號(hào)“65”,“B”字符編號(hào)是“66”。

大家需要清楚對(duì)于有些字符編碼的編號(hào)就是存儲(chǔ)的二進(jìn)制序列,如ASCII編碼;有些字符編碼的編號(hào)跟存儲(chǔ)的二進(jìn)制序列并不一樣,比如GB2312、Unicode等。

另外:編號(hào)字符集合是有范圍限制的,比如ASCII字符集范圍是0~127,ISO-8859-1范圍是0~256,而GB2312是用一個(gè)94*94的二維矩陣空間來(lái)表示,Unicode是用Plane平面空間的概念來(lái)表示,這稱為字符集的編號(hào)空間。

編號(hào)空間中的一個(gè)位置稱為碼點(diǎn)(?Code Point 代碼點(diǎn)?)。一個(gè)字符占用的碼點(diǎn)所在的坐標(biāo)(非負(fù)整數(shù)值對(duì))或所代表的非負(fù)整數(shù)值,就是該字符的碼值(碼點(diǎn)編號(hào))。

ASCII碼點(diǎn)編號(hào):

6.5、第三層:字符編碼方式 CEF

抽象字符集和編號(hào)字符集是站在方便我們理解的角度來(lái)看的,所以最后我們需要翻譯成計(jì)算機(jī)能懂的語(yǔ)言,將十進(jìn)制的編號(hào)轉(zhuǎn)換成二進(jìn)制的形式。

因此:字符編碼方式就是將字符集的碼點(diǎn)編號(hào),轉(zhuǎn)換成二進(jìn)制碼元序列( Code Unit Sequence )的過程。

碼元:字符編碼的最小處理單元,比如ASCII一個(gè)字符等于一個(gè)字節(jié),屬于單字節(jié)碼元;UTF-16一個(gè)字符等于兩個(gè)字節(jié),處理過程是按字“word”來(lái)處理,所以是雙字節(jié)碼元;UTF-8是多字節(jié)編碼,有單字節(jié)字符,也有多字節(jié)字符,每次處理是按單個(gè)單個(gè)字節(jié)解析處理,所以處理最小單位是字節(jié),也屬于單字節(jié)碼元。

這里大家可能會(huì)有疑問:十進(jìn)制直接轉(zhuǎn)二進(jìn)制不就好了嗎,為什么要單獨(dú)抽出這么一層?

早期的字符編碼確實(shí)也是這么處理的,十進(jìn)制和二進(jìn)制之間是直接轉(zhuǎn)換過去的,比如ASCII碼,字符“A”的十進(jìn)制是“65”,那對(duì)應(yīng)的二進(jìn)制就是“1000001”,同時(shí)存儲(chǔ)到硬盤里的也是這個(gè)二進(jìn)制,所以那時(shí)候的編碼比較簡(jiǎn)單。

隨著后來(lái)多字節(jié)字符編碼(Muilti-Bytes Character Set,MBCS多字節(jié)字符集)的出現(xiàn),字符編號(hào)和二進(jìn)制之間不是直接轉(zhuǎn)換過去的,比如GB2312編碼,“萬(wàn)”字的區(qū)位編號(hào)是“45,82”,對(duì)應(yīng)的二進(jìn)制機(jī)內(nèi)碼卻是“1100 1101 1111 0010”(其十進(jìn)制是“205,242”)。

如果這里不轉(zhuǎn)換直接映射成二進(jìn)制碼會(huì)出什么問題呢?“萬(wàn)”字的字符編號(hào)“45,82”,45在ASCII里是“-”,82是“U”,那到底是顯示兩個(gè)字符“-U”還是顯示一個(gè)字符“萬(wàn)”字,為了避免這種沖突 所以增加了前綴處理,詳細(xì)的過程會(huì)在下文具體來(lái)講解。

6.6、第四層:字符編碼方案 CES

字符編碼方案也稱作“序列化格式“(?Serialization Format?),指的是將字符編號(hào)進(jìn)行編碼之后的碼元序列映射為字節(jié)序列(即字節(jié)流)的形式,以便經(jīng)過編碼后的字符能在計(jì)算機(jī)中進(jìn)行處理、存儲(chǔ)和傳輸。

字符編碼方式CEF有點(diǎn)像我們數(shù)據(jù)庫(kù)結(jié)構(gòu)設(shè)計(jì)里的邏輯設(shè)計(jì),而這一層編碼方案CES就像是物理設(shè)計(jì)了,將碼元序列映射為跟特定的計(jì)算機(jī)系統(tǒng)平臺(tái)相關(guān)的物理意義上的二進(jìn)制過程。

這里大家可能又會(huì)有疑問:為什么二進(jìn)制的碼元序列和實(shí)際存儲(chǔ)的二進(jìn)制又會(huì)不一樣呢?

這主要是計(jì)算機(jī)的大小端序造成的,具體端序內(nèi)容會(huì)在UTF-16編碼部分詳細(xì)介紹。

“大小端序名詞”出自Jonathan Swift的《格列夫游記》一書 :

所有人都認(rèn)為,吃雞蛋前,原始的方法是打破雞蛋較大的一端??墒钱?dāng)今皇帝的祖父小時(shí)候吃雞蛋,一次按古法打雞蛋時(shí)碰巧將一個(gè)手指弄破了,因此他的父親,當(dāng)時(shí)的皇帝,就下了一道敕令,命令全體臣民吃雞蛋時(shí)打破雞蛋較小的一端,違令者重罰。

老百姓們對(duì)這項(xiàng)命令極為反感。歷史告訴我們,由此曾發(fā)生過六次叛亂,其中一個(gè)皇帝送了命,另一個(gè)丟了王位…關(guān)于這一爭(zhēng)端,曾出版過幾百本大部著作,不過大端派的書一直是受禁的,法律也規(guī)定該派的任何人不得做官。

▲ 圖片引用自《面試必考,史上最通俗大小端字節(jié)序詳解》

對(duì)大小端字節(jié)序問題感興趣的可以詳讀:《腦殘式網(wǎng)絡(luò)編程入門(九):面試必考,史上最通俗大小端字節(jié)序詳解》一文。

七、常見字符編碼1:ASCII

很久以前:計(jì)算機(jī)制造商都是按各自的方式來(lái)將字符渲染到屏幕上,當(dāng)時(shí)的計(jì)算機(jī)動(dòng)不動(dòng)可就是一套房子的大小,這家伙可不是誰(shuí)都能玩的起的,那時(shí)人們并不關(guān)心計(jì)算機(jī)如何交流。

隨著上世紀(jì)七八十年代微處理器的出現(xiàn),計(jì)算機(jī)變得越來(lái)越小,個(gè)人計(jì)算機(jī)開始進(jìn)入大眾的視線,隨后出現(xiàn)了井噴式的發(fā)展,但是之前廠商都是各自為政,沒考慮過自家的產(chǎn)品要兼容別人家的東西,導(dǎo)致在不同計(jì)算機(jī)體系間的數(shù)據(jù)轉(zhuǎn)換變得十分蛋疼,因此美國(guó)的標(biāo)準(zhǔn)協(xié)會(huì)在1967年制定出了ASCII編碼,到目前為止共定義了128個(gè)字符。

ASCII 編碼:

(注意:該表是列表示字節(jié)高 4 位。上圖引用自《字符編碼那點(diǎn)事:快速理解ASCII、Unicode、GBK和UTF-8》)

其中:前 32 個(gè)(0~31)是不可見的控制字符,32~126 是可見字符,127 是 DELETE 命令(鍵盤上的 DEL 鍵)。

其實(shí):早在ASCII之前,IBM在1963年也推出過一套字符編碼系統(tǒng)EBCDIC,跟ASCII碼一樣囊括了控制字符、數(shù)字、常用標(biāo)點(diǎn)、大小寫英文字母。

EBCDIC 編碼:

但是:他的字符編號(hào)并不是連續(xù)的,這給后續(xù)程序處理帶來(lái)了麻煩,后來(lái)ASCII 編碼吸取了 EBCDIC 的經(jīng)驗(yàn)教訓(xùn),給英文單詞分配了連續(xù)的編碼,方便程序處理,因此被后來(lái)廣泛接受。

ASCII 和 EBCDIC 編碼相比:除了字符連續(xù)排列之外,最大的優(yōu)點(diǎn)是ASCII 只用了一個(gè)字節(jié)的低 7 位,最高位永遠(yuǎn)是 0??蓜e小看了這個(gè)最高位的 0,看似無(wú)足輕重,但這是ASCII設(shè)計(jì)最成功的地方,后面介紹各編碼原理的時(shí)候你會(huì)發(fā)現(xiàn),正是因?yàn)檫@個(gè)高位0,其它編碼規(guī)范才能對(duì) ASCII 碼無(wú)縫兼容,使得 ASCII 被廣泛接受。

八、常見字符編碼2:ISO-8859系列

美國(guó)市場(chǎng)雖然統(tǒng)一了字符編碼,但是計(jì)算機(jī)制造商在進(jìn)入歐洲市場(chǎng)的時(shí)候又遇到了麻煩。。。

歐洲的主流語(yǔ)言雖然也是用拉丁字母,但卻存在很多擴(kuò)展體,比如法語(yǔ)的“é”,挪威語(yǔ)中的“?”,都無(wú)法用 ASCII 表示。但是大家發(fā)現(xiàn)ASCII后面的128個(gè)還沒有被使用可以利用起來(lái),這對(duì)于歐洲主流語(yǔ)言就足夠了。

于是就有了大家所熟知的這個(gè)ISO-8859-1(Latin-1),它只是擴(kuò)展了ASCII后128個(gè)字符,還是屬于單字節(jié)編碼。同時(shí)為了兼容原先的 ASCII碼,當(dāng)最高位是0的時(shí)候仍然表示原先的 ASCII 字符不變,當(dāng)最高位是1的時(shí)候表示擴(kuò)展的歐洲字符。

但是到這里還沒有完:剛說(shuō)了這只是歐洲主流的語(yǔ)言,但主流語(yǔ)言里沒有法語(yǔ)使用的??、?、??三個(gè)字母,也沒有芬蘭語(yǔ)使用的??、?、?、??,而單字節(jié)編碼里的256個(gè)碼點(diǎn)都被用完了,于是就出現(xiàn)了更多的變種?ISO-8859-2/3/.../16?系列,他們都兼容 ASCII,但彼此間又不完全兼容。

ISO-8859-n系列字符集如下:

  • 1)ISO8859-1 字符集,也就是 Latin-1,是西歐常用字符,包括德法兩國(guó)的字母;

  • 2)ISO8859-2 字符集,也稱為 Latin-2,收集了東歐字符;

  • 3)ISO8859-3 字符集,也稱為 Latin-3,收集了南歐字符;

  • 4)ISO8859-4 字符集,也稱為 Latin-4,收集了北歐字符;

  • 5)ISO8859-5 字符集,也稱為 Cyrillic,收集了斯拉夫語(yǔ)系字符;

  • 6)ISO8859-6 字符集,也稱為 Arabic,收集了阿拉伯語(yǔ)系字符;

  • 7)ISO8859-7 字符集,也稱為 Greek,收集了希臘字符;

  • .......

九、常見字符編碼3:GB系列

9.1、概述

當(dāng)計(jì)算機(jī)進(jìn)入東亞國(guó)家的時(shí)候,廠商們更傻眼了,美國(guó)和歐洲國(guó)家語(yǔ)言基本都是表音字符,一個(gè)字節(jié)就足夠用了,但亞洲國(guó)家有不少是表意字符,字符個(gè)數(shù)動(dòng)輒幾萬(wàn)十幾萬(wàn)的,一個(gè)字節(jié)完全不夠用。

所以我們國(guó)家有關(guān)部門按照ISO規(guī)范設(shè)計(jì)了GB2312雙字節(jié)編碼。但是GB2312是一個(gè)封閉字符集,只收錄了常用字符總共也就7000多個(gè)字符,因此為了擴(kuò)充更多的字符包括一些生僻字,才有了之后的GBK、GB18030、GB13000(“GB” 為 “國(guó)標(biāo)” 的漢語(yǔ)拼音首字母縮寫)。

按照 GB 系列編碼方案,在一段文本中,如果一個(gè)字節(jié)是 0~127,那么這個(gè)字節(jié)的含義與 ASCII 編碼相同,否則,這個(gè)字節(jié)和下一個(gè)字節(jié)共同組成漢字(或是 GB 編碼定義的其他字符),所以GB系列都是兼容ASCII編碼的。

9.2、GB2312

GB2312是使用兩個(gè)字節(jié)來(lái)表示漢字的編碼標(biāo)準(zhǔn),共收入漢字6763個(gè)和非漢字圖形字符682個(gè)。

為了避免與 ASCII 字符編碼(0~127)相沖突,規(guī)定表示一個(gè)漢字的編碼字節(jié)其值必須大于127(即字節(jié)的最高位為 1?),并且必須是兩個(gè)大于 127 的字節(jié)連在一起來(lái)共同表示一個(gè)漢字(?GB2312 為雙字節(jié)編碼),所以GB2312 屬于變長(zhǎng)編碼,當(dāng)是英文字符的時(shí)候占一個(gè)字節(jié),中文字符的時(shí)候占兩個(gè)字節(jié),可以認(rèn)為 GB2312是對(duì) ASCII 的中文擴(kuò)展。

GB2312字符集編號(hào)空間是一個(gè)94*94的二維表,行表示區(qū)(高位字節(jié)),列表示位(低位字節(jié)),每區(qū)有94個(gè)位,每個(gè)區(qū)位對(duì)應(yīng)一個(gè)字符,稱為區(qū)位碼。區(qū)位碼上加2020H,就得到國(guó)標(biāo)碼,國(guó)標(biāo)碼上加8080H,就得到常用的計(jì)算機(jī)機(jī)內(nèi)碼。

這里引入了區(qū)位碼、國(guó)標(biāo)碼、機(jī)內(nèi)碼概念,下面我們說(shuō)下三者的關(guān)系。

9.2.1國(guó)標(biāo)碼

國(guó)標(biāo)碼是我國(guó)漢字信息交換的標(biāo)準(zhǔn)編碼,規(guī)定由4位16進(jìn)制數(shù)組成,用兩個(gè)低7位字節(jié)表示,為了避開 ASCII 字符中的前32個(gè)控制指令字符,所以每個(gè)字節(jié)都是從第33個(gè)編號(hào)開始。

如下圖所示:

9.2.2區(qū)位碼

由于上述國(guó)標(biāo)碼的16進(jìn)制可編碼區(qū)不夠直觀不方便我們使用,所以我們把他映射成了十進(jìn)制的94*94二維表編號(hào)空間,我們稱之為區(qū)位碼,同時(shí)區(qū)位碼也可以當(dāng)成一種外碼使用,輸入法可以直接切換成區(qū)位碼進(jìn)行漢字輸入。

不過這種輸入法無(wú)規(guī)則可言 人們很難記住區(qū)位編號(hào),用的人也不多了。

下圖是區(qū)位碼的二維表,比如“萬(wàn)”字是45 區(qū) 82 位,所以“萬(wàn)” 字的區(qū)位碼是“45,82”。

其中:

  • 1)01~09區(qū)(682個(gè)):特殊符號(hào)、數(shù)字、英文字符、制表符等(包括拉丁字母、希臘字母、日文平假名及片假名字母、俄語(yǔ)西里爾字母等在內(nèi)的682個(gè)全角字符);

  • 2)10~15區(qū):空區(qū),留待擴(kuò)展;

  • 3)16~55區(qū)(3755個(gè)):常用漢字(也稱一級(jí)漢字),按拼音排序;

  • 4)56~87區(qū)(3008個(gè)):非常用漢字(也稱二級(jí)漢字),按部首/筆畫排序;

  • 5)88~94區(qū):空區(qū),留待擴(kuò)展。

9.2.3機(jī)內(nèi)碼

GB2312國(guó)標(biāo)碼規(guī)范是覆蓋掉ASCII中可見部分的符號(hào)和英文字母,使用兩個(gè)7位碼將其中的英文字母和符號(hào)重新編入。

但是這樣產(chǎn)生一個(gè)弊端:早期用ASCII碼編碼的英文文章無(wú)法打開,一打開就是亂碼,也就是說(shuō)應(yīng)該要兼容早期ASCII碼而不是覆蓋它。

后來(lái)微軟為了解決這個(gè)問題:將字節(jié)的最高位設(shè)為1,因?yàn)锳SCII中使用7位,最高位為0,轉(zhuǎn)換后的編碼稱為機(jī)內(nèi)碼(內(nèi)碼),這種方式本質(zhì)上是修改了GB2312的編碼標(biāo)準(zhǔn),最后被大家接受沿用。

總結(jié)下三者轉(zhuǎn)換關(guān)系:區(qū)位碼 ---> 區(qū)碼和位碼分別 + 32(即 + 20H )得到國(guó)標(biāo)碼 ---> 再分別 + 128(即 + 80H)得到機(jī)內(nèi)碼(與 ACSII 碼不再?zèng)_突)。

9.3、GBK

GBK即“國(guó)標(biāo)擴(kuò)展”的意思,因?yàn)镚B2312雙字節(jié)的最高位都要求大于1,上限也不會(huì)超過1萬(wàn)個(gè)字符,所以對(duì)此進(jìn)行了擴(kuò)展,對(duì)GB2312的字符不重新編碼直接沿用,因此完全兼容GB2312。

GBK雖然也是雙字節(jié)編碼,但是只要求第一個(gè)字節(jié)大于 127 就固定表示這是一個(gè)漢字的開始,正因?yàn)槿绱?,GBK的編碼空間比GB2312大很多。

GBK 整體編碼范圍為 8140-FEFE,首字節(jié)在 81-FE 之間,尾字節(jié)在 40-FE 之間,剔除 xx7F 一條線,總計(jì) 23940 個(gè)碼位,共收入 21886 個(gè)漢字和圖形符號(hào)。其中 GBK/1 收錄除 GB 2312 字符外的其他增補(bǔ)字符,GBK/2 收錄 GB2312 字符,GBK/3 收錄 CJK 字符,GBK/4 收錄 CJK 字符和增補(bǔ)字符,GBK/5 為非中文字符,UDC 為用戶自定義字符。

詳細(xì)如下如所示:

這里大家可能會(huì)有兩個(gè)疑問:為什么尾字節(jié)要從40開始,而不是00開始?為什么要排除 FF、xx7F這兩條線的編號(hào)?

GBK的尾字節(jié)編碼高位沒有強(qiáng)制要求是1,當(dāng)高位是0時(shí)跟ASCII碼是沖突的,ASCII碼里00-40之間大部分都是控制字符,所以排除控制字符主要是為了防止丟失高字節(jié)導(dǎo)致出現(xiàn)系統(tǒng)性嚴(yán)重后果。

排除FF是為了兼容GB2312,GB2312這個(gè)位是保留不使用的;而7F表示DEL字符就是向后刪除一個(gè)字符,如果傳輸過程中丟失首字節(jié)那么就會(huì)出現(xiàn)嚴(yán)重的后果,所以需要將xx7F也排除,這是所有編碼方案都需要注意的地方。

9.4、GB18030

隨著計(jì)算機(jī)的發(fā)展,GBK的2萬(wàn)多個(gè)字符也還是扛不住。

于是2000年我國(guó)又制定了新標(biāo)準(zhǔn) GB18030,用來(lái)替代 GBK 標(biāo)準(zhǔn)。GB18030是強(qiáng)制性標(biāo)準(zhǔn),現(xiàn)在在中國(guó)大陸銷售的軟件都支持 GB18030。

GB18030其實(shí)是對(duì)齊Unicode標(biāo)準(zhǔn)的,里面包括了所有Unicode字符集,也算是Unicode的一種實(shí)現(xiàn)(UTF)。

那既然有了UTF我們?yōu)槭裁催€要搞一套Unicode實(shí)現(xiàn)?

主要是UTF-8/UCS-2他們是不兼容GB2312的,如果直接升級(jí)那么就全亂碼了,所以GB18030是為了兼容GB系列,是GBK、GB2312的超集,當(dāng)我們?cè)鹊腉B2312(GBK)軟件考慮升級(jí)到國(guó)際化Unicode時(shí),可以直接使用GB18030進(jìn)行升級(jí)。

GB18030雖然也是GB2312的擴(kuò)展,但它和GBK的擴(kuò)展方式不一樣,GBK主要是充分利用了GB2312的一些沒定義的編碼空間,而GB18030采用的是字節(jié)變長(zhǎng)編碼,單字節(jié)區(qū)兼容ASCII、雙字節(jié)區(qū)兼容GBK、四字節(jié)區(qū)對(duì)齊所有Unicode 碼位。

實(shí)現(xiàn)原理上主要是采用第二字節(jié)未使用到的0x30~0x39編碼空間來(lái)判斷是否四字節(jié)。

具體就是:

  • 1)單字節(jié),其值從0到0x7F。

  • 2)?雙字節(jié),第一個(gè)字節(jié)的值從0x81到0xFE,第二個(gè)字節(jié)的值從0x40到0xFE(不包括0x7F)。

  • 3)?四字節(jié),第一個(gè)字節(jié)的值從0x81到0xFE,第二個(gè)字節(jié)的值從0x30到0x39,第三個(gè)字節(jié)的值從0x81到0xFE,第四個(gè)字節(jié)的值從0x30到0x39。

十、常見字符編碼4:UNICODE

10.1、背景介紹

在統(tǒng)一碼之前,各國(guó)創(chuàng)造了大量的節(jié)編碼標(biāo)準(zhǔn),有單字節(jié)的、雙字節(jié)的(如 GB 2312、Shift JIS、Big5 、ISO8859等),各自又相互不兼容。在1987 年,蘋果、Sun、微軟等公司開始討論囊括全世界所有字符的統(tǒng)一編碼標(biāo)準(zhǔn),組成了 Unicode 聯(lián)盟,這個(gè)期間做了很多研討工作,討論核心要點(diǎn)如下。

1)目前世界上有多少個(gè)字符,需要幾個(gè)字節(jié)存儲(chǔ)?

工作組統(tǒng)計(jì)了當(dāng)時(shí)全世界的報(bào)紙等刊物,結(jié)論是兩個(gè)字節(jié)足以囊括全世界有實(shí)用意義的字符(當(dāng)然這只統(tǒng)計(jì)了當(dāng)前使用的字符,不包括古代語(yǔ)言或者廢棄語(yǔ)言)。

2)采用固定長(zhǎng)度編碼還是變長(zhǎng)編碼?

一種采用變長(zhǎng)編碼形式,對(duì)于 ASCII 字符使用一個(gè)字節(jié),其他字符使用兩個(gè)字節(jié),類似 GBK。另一種采用定長(zhǎng)編碼形式,不管是不是 ASCII 字符統(tǒng)一使用兩個(gè)字節(jié)。

方案選擇上主要從計(jì)算機(jī)處理過程中的時(shí)間和空間兩個(gè)維度,也就是編解碼的執(zhí)行效率和存儲(chǔ)大小兩方面。

最后結(jié)論是采用雙字節(jié)定長(zhǎng)編碼,因?yàn)槎ㄩL(zhǎng)帶來(lái)的空間變大在整體傳輸、存儲(chǔ)成本上其實(shí)影響并不大,而定長(zhǎng)編碼處理效率會(huì)明顯高于變長(zhǎng)編碼,所以早期 Unicode 采用了定長(zhǎng)編碼形式。

3)中、日、韓中有很多相近的表意文字是否可以統(tǒng)一?

由于漢字表意文字字符量較大,如果可以統(tǒng)一那么能大幅減少收錄漢字的數(shù)量。

所以最初收錄漢字遵循兩個(gè)基本原則:表意文字認(rèn)同原則和字源分離原則。

所謂表意文字認(rèn)同原則:即“只對(duì)字,不對(duì)形”編碼,將同一字的不同字形(即異體字)合并。例如“房”字的第一筆,在中日韓的寫法都不同,但它本身是同一個(gè)字,只給一個(gè)編碼,而寫法的不同交由字體進(jìn)行區(qū)分。

字源分離原則:是指一個(gè)字源中同時(shí)收錄了同一個(gè)字的不同字形,則給予兩個(gè)字形分別編碼。例如:之前GBK中就收錄了“戶”、“戶”、“戸”三個(gè)字,那么Unicode也需要保留三個(gè)字,如果直接合并會(huì)造成使用上的困擾。

例如下面這句話如果不做字源分離,會(huì)是什么情況呢?

原句 :戶有三種寫法,分別是“戶”、“戶”、“戸”,

改寫后:戶有三種寫法,分別是“戶”、“戶”、“戶”

10.2、Unicode介紹

Unicode 稱為統(tǒng)一碼(也叫萬(wàn)國(guó)碼),是按現(xiàn)代編碼模型進(jìn)行設(shè)計(jì)的一套字符編碼體系,涵蓋抽象字符集、編號(hào)、邏輯編碼、編碼實(shí)現(xiàn)。

Unicode是為了解決傳統(tǒng)的字符編碼方案的局限而產(chǎn)生的,在這種語(yǔ)言環(huán)境下,不會(huì)再有語(yǔ)言的編碼沖突,可以在同屏下顯示任何國(guó)家的語(yǔ)言。

UTF-n編碼(Unicode Transformation Format Unicode字符集轉(zhuǎn)換格式,n表示碼元位數(shù))是Unicode這套編碼體系里的編碼實(shí)現(xiàn)CES部分,像UTF-8、UTF-16、UTF-32都是將數(shù)字轉(zhuǎn)換到實(shí)際的二進(jìn)制編碼實(shí)現(xiàn),Unicode的編碼實(shí)現(xiàn)除了UTF系列之外,還有UCS-2/4,GB18030等。但是現(xiàn)在很多人誤把Unicode當(dāng)成只是一個(gè)字符編號(hào),這其實(shí)是不對(duì)的。

Unicode可以容納世界上所有國(guó)家的文字和符號(hào),其編號(hào)范圍是0-0x10FFFF,有1,114,112個(gè)碼位,為了方便管理劃分成17個(gè)平面,現(xiàn)已定義的碼位有238,605個(gè),分布在平面0、平面1、平面2、平面14、平面15、平面16。其中平面0又稱為基本多語(yǔ)言平面(Basic Multilingual Plane,簡(jiǎn)稱BMP),這個(gè)平面基本涵蓋了當(dāng)今世界上正在使用中的常用字符。我們平常用到的字符,一般都是位于 BMP 平面上的,其范圍擁有 65,536 個(gè)碼點(diǎn),其他平面統(tǒng)稱增補(bǔ)平面,關(guān)于平面的概念會(huì)在UTF-16章節(jié)詳細(xì)介紹。

10.3、與UCS的關(guān)系

說(shuō)起Unicode我們不得不提UCS(全稱Universal Multiple-Octet Coded Character Set 通用多八位編碼字符集),國(guó)際標(biāo)準(zhǔn)編號(hào)ISO/IEC 10646,是由 ISO 和 IEC 兩家國(guó)際標(biāo)準(zhǔn)組織聯(lián)合成立的工作組設(shè)計(jì)的一套新的統(tǒng)一字符集項(xiàng)目,目的與Unicode 聯(lián)盟一樣致力于開發(fā)一款全世界通用的編碼集。

早在1984 年ISO 和 IEC 兩家組織就成立了一個(gè)聯(lián)合工作組來(lái)設(shè)計(jì)一套新的統(tǒng)一字符集標(biāo)準(zhǔn),但是這兩個(gè)組織都不知道對(duì)方的存在,直到Unicode聯(lián)盟1988年發(fā)布了Unicode草案(UCS草案1989年發(fā)布),才發(fā)現(xiàn)大家在做同一件事,沒有必要搞兩套標(biāo)準(zhǔn) 所以后面又考慮合并。

由于UCS 最初設(shè)計(jì)的是 31 位編碼空間(UCS-4編碼實(shí)現(xiàn)),可以容納 2^31 約 21 億個(gè)字符,而Unicode是16位空間(UTF-16編碼實(shí)現(xiàn)),所以最開始Unicode 打算作為 UCS 的真子集,即 Unicode 中的每個(gè)字符都存在于 UCS 中,而且兩者的碼點(diǎn)相同,但 UCS 中的字符(編號(hào)超過65,536的)則不一定存在于 Unicode 中。

不過:由于雙方利益關(guān)系并沒有說(shuō)誰(shuí)解散誰(shuí),最后雙方作出一些妥協(xié)保持一致共同發(fā)展,兩個(gè)標(biāo)準(zhǔn)中相同字符的編碼(碼點(diǎn))必須是一樣的。這是一個(gè)屁股決定腦袋的決策,如果最初Unicode知道UCS的存在,就不會(huì)再出現(xiàn)Unicode了。

當(dāng)然合并工作不是一蹴而就的而是經(jīng)過多輪迭代, ISO/IEC 和 Unicode在 1993 年發(fā)布了第一版相互兼容版本,到了 1996年Unicode 2.0標(biāo)準(zhǔn)發(fā)布時(shí),Unicode 字符集和 UCS 字符集(即 ISO/IEC 10646-1?)基本保持了一致,同時(shí)Unicode為了跟UCS的四字節(jié)保持一致推出了UTF-32編碼實(shí)現(xiàn),UCS為了跟Unicode的兩字節(jié)保持一致推出了UCS-2編碼實(shí)現(xiàn)。

所以:現(xiàn)在我們可以認(rèn)為UCS和Unicode是同一個(gè)東西,比如我們常見的java內(nèi)部運(yùn)行就采用的是UTF-16編碼,而window操作系統(tǒng)采用的是UCS-2,他們都是同一個(gè)Unicode標(biāo)準(zhǔn)。

為什么這里使用的是2字節(jié)編碼,而不是4字節(jié)呢?先留個(gè)懸念,后續(xù)會(huì)詳細(xì)講解。

10.4、UTF-16(Java內(nèi)部編碼)

UTF是Unicode Transfer Format的縮寫,即把Unicode轉(zhuǎn)做某種格式的意思,所以UTF-16是Unicode編碼里的其中一種實(shí)現(xiàn)方式,16代表的是字節(jié)位數(shù),占兩個(gè)字節(jié)(UTF-32則表示4個(gè)字節(jié))。

Unicode?設(shè)計(jì)之初是采用UTF-16這種雙字節(jié)定長(zhǎng)編碼的,其字符編號(hào)就是對(duì)應(yīng)的二進(jìn)制編號(hào),也就是說(shuō)第二層的CCS和第三層的CEF是一致的。比如漢字“萬(wàn)”的 Unicode 碼點(diǎn)是 “U+4E07”,其二進(jìn)制序列就是直譯的“0100 1110 0000 0111?”,這種編碼方式的優(yōu)點(diǎn)是高效,不需要檢查標(biāo)志位,但缺點(diǎn)是不兼容ASCII,ASCII編碼的文本都會(huì)顯示亂碼。

不過:后來(lái)Unicode聯(lián)盟發(fā)現(xiàn) 16 位編碼空間根本不夠用,與此同時(shí) ISO/IEC組織也覺得 UCS的 32 位編碼空間太多了,實(shí)際中根本沒有幾十億字符,也挺浪費(fèi)空間的。

所以最終 Unicode 聯(lián)盟和 ISO/IEC 工作組達(dá)成一致:兩者使用統(tǒng)一的編碼空間“?0000 ~ 10FFFF”(即 UCS 保證永遠(yuǎn)不分配大于 10FFFF 的字符碼點(diǎn)),而且雙方在字符編碼上保持同步,即一方標(biāo)準(zhǔn)中增加了字符,也要通知另一方同步。

于是:Unicode在UTF-16基礎(chǔ)上拓展編碼空間到 21 位,UCS則搞了一個(gè)雙字節(jié)的UCS-2編碼實(shí)現(xiàn)。

UTF-16 編碼是雙字節(jié)的,上限也只有6w多個(gè)碼點(diǎn),怎么讓他支持到10FFFF(100w+)個(gè)碼點(diǎn)呢?

本質(zhì)就是:多加幾個(gè)字節(jié)來(lái)表示更多的字符,只是UTF-16不像UCS那樣采用定長(zhǎng)4字節(jié),而是使用變長(zhǎng)的形式,但是這個(gè)跟UTF-8變長(zhǎng)方式又不太一樣,他是采用代理對(duì)的方式實(shí)現(xiàn),大部分常用字符用一個(gè)碼元表示(定長(zhǎng)2個(gè)字節(jié)),其他擴(kuò)展的特殊字符用兩個(gè)碼元表示(定長(zhǎng)4字節(jié))。

10.4.1代理對(duì)

UTF-16跟UTF-8、GB系列等都算是變長(zhǎng)字節(jié),但是設(shè)計(jì)初衷卻不一樣,像GBK是為了兼容ASCII,但是UTF-16一開始就沒考慮要兼容ASCII,所以他的變長(zhǎng)是為了節(jié)約存儲(chǔ)空間而采用的自然增長(zhǎng)方案,當(dāng)空間不夠的時(shí)候增長(zhǎng)到4個(gè)字節(jié)。

那問題來(lái)了,我怎么知道存儲(chǔ)的4個(gè)字節(jié)是表示一個(gè)字符,還是兩個(gè)字符呢?比如當(dāng)程序遇到字節(jié)序列01001110 00101101 01010110 11111101時(shí),到底是判斷成一個(gè)字符還是兩個(gè)字符?

這就需要一個(gè)前導(dǎo)識(shí)別,比如GB2312識(shí)別第一個(gè)字節(jié)高位是不是1來(lái)判斷是單字節(jié)還是雙字節(jié),但是UTF-16的高位1已經(jīng)被用來(lái)編碼了,當(dāng)然這也難不倒我們,第一位被用了那么就用前幾位的組合形式。

UTF-16采用了代理對(duì)來(lái)解決,也就是高半?yún)^(qū)編碼(前兩個(gè)字節(jié))范圍D800-DBFF(稱為代理碼點(diǎn)),低半?yún)^(qū)編碼(后兩個(gè)字節(jié))范圍DC00-DFFF,組成一個(gè)四個(gè)字節(jié)表示的字符。

上述前導(dǎo)6位組合也是有講究的,ISO組織要求編號(hào)范圍是0~10FFFF,也就是說(shuō)用20位就可以表示10FFFF個(gè)字符,對(duì)于雙碼元就是每個(gè)碼元各自負(fù)責(zé)10位,一個(gè)碼元是16位,數(shù)字位占去10位后,剩下的6位做為前導(dǎo)位。

當(dāng)UTF-16使用一個(gè)碼元表示的時(shí)候,Unicode字符編號(hào)跟碼元序列是等值映射的,但是當(dāng)采用雙碼元后,字符編號(hào)跟碼元序列就需要轉(zhuǎn)換了。

下面是碼元和Unicode編號(hào)值之間的計(jì)算公式。

換算碼元序列(CH高半?yún)^(qū)/CL低半?yún)^(qū)):

換算字符編號(hào)(CH高半?yún)^(qū)/CL低半?yún)^(qū)):

10.4.2平面空間

UTF-16把編碼空間0000 ~ 10FFFF切成了17個(gè)平面,其實(shí)就是劃分成17個(gè)區(qū)塊,每個(gè)平面空間碼點(diǎn)數(shù)都是=65536個(gè),第一個(gè)平面稱為基本多語(yǔ)言平面(Basic Multilingual Plane,簡(jiǎn)稱BMP),這個(gè)平面涵蓋了當(dāng)今世界上最常用的字符,固定使用定長(zhǎng)兩個(gè)字節(jié),除此之外的字符都放到增補(bǔ)平面里,都是使用兩個(gè)碼元的定長(zhǎng)4個(gè)字節(jié)。

下面是各個(gè)平面的用途:

增補(bǔ)平面的編號(hào)是采用雙碼元4個(gè)字節(jié)來(lái)表示的,去除代理對(duì)之后有效位數(shù)是20位,然后將這20位的編號(hào)再劃成16個(gè)平面區(qū)域,其中高半?yún)^(qū)的數(shù)字位里取出4位表示平面,剩下的16位表示每個(gè)平面可以表示的字符數(shù)也就是2的16次方65536個(gè)(兩個(gè)字節(jié)大?。?/p>

UTF-16可看成是UCS-2的父集。在沒有輔助平面前,UTF-16與UCS-2所指的是同一的意思。但當(dāng)引入輔助平面字符后,就稱為UTF-16了。

10.4.3字節(jié)序

字節(jié)序顧名思義是指字節(jié)的順序,對(duì)于單字節(jié)編碼來(lái)說(shuō),一個(gè)字符對(duì)應(yīng)一個(gè)字節(jié),也就不存在字節(jié)序問題。但是對(duì)于UTF-16這種定長(zhǎng)多字節(jié)編碼,就有字節(jié)順序問題了。

字節(jié)序其實(shí)跟操作系統(tǒng)和底層硬件有關(guān),不僅只是UTF-16這種多字節(jié)編碼存在字節(jié)序,只要是多字節(jié)類型的數(shù)據(jù)都存在字節(jié)順序問題,比如short、int、long。

為了方便說(shuō)明,我們這里舉個(gè)例子:比如存一個(gè)整數(shù)值“305419896”對(duì)應(yīng)16進(jìn)制是0x12345678,有人習(xí)慣從左到右按順序去存,也有人說(shuō)高位當(dāng)然要放到高位地址而低位放到低位地址,要從右往左存。

于是就有了下面兩種存取方式:

其實(shí)這兩種方式?jīng)]有孰優(yōu)孰劣,只是我們認(rèn)知習(xí)慣有所不同 最終的設(shè)計(jì)不同,說(shuō)來(lái)這都是阿拉伯人的鍋啊,為什么數(shù)字高位非要在左邊,這也引起了著名的大小端之爭(zhēng)。

因此字節(jié)序也就有了大端和小端的概念,也形成了各自的陣營(yíng),比如Windows、FreeBSD、Linux 是小端序,Mac是大端序。其實(shí)大小端序并沒有技術(shù)上的好壞之分。

小端序(Little-Endian):就是低位字節(jié)(即小端字節(jié)、尾端字節(jié))存放在內(nèi)存的低地址,而高位字節(jié)(即大端字節(jié)、頭端字節(jié))存放在內(nèi)存的高地址。

大端序(Big-Endian?):就是高位字節(jié)(即大端字節(jié)、頭端字節(jié))存放在內(nèi)存的低地址,低位字節(jié)(即小端字節(jié)、尾端字節(jié))存放在內(nèi)存的高地址。

▲ 圖片引用自《面試必考,史上最通俗大小端字節(jié)序詳解》

對(duì)大小端字節(jié)序問題感興趣的可以詳讀:《腦殘式網(wǎng)絡(luò)編程入門(九):面試必考,史上最通俗大小端字節(jié)序詳解》一文。

10.5、UTF-8

10.5.1概述

Unicode還是UCS最初都是采用多字節(jié)定長(zhǎng)編碼,由于沒有兼容現(xiàn)有的 ASCII 標(biāo)準(zhǔn)的文件和軟件,新標(biāo)準(zhǔn)很難被推廣,于是兼容ASCII版本的UTF-8就誕生了。

UTF-8(8-bit Unicode Transformation Format)是一種針對(duì)Unicode的可變長(zhǎng)度字符編碼,是現(xiàn)代字符編碼模型中的第三層 CEF 。它可以用一至四個(gè)字節(jié)對(duì) Unicode 字符集中的所有有效編碼點(diǎn)進(jìn)行編碼,屬于Unicode標(biāo)準(zhǔn)的一部分,UTF-8 就是為了解決向后兼容 ASCII 碼而設(shè)計(jì),Unicode 中前 128 個(gè)字符(與 ASCII 碼一一對(duì)應(yīng)),使用與 ASCII 碼相同的二進(jìn)制值的單個(gè)字節(jié)進(jìn)行編碼,這使得原來(lái)處理 ASCII 字符的軟件無(wú)須或只須做少部分修改,即可繼續(xù)使用。因此,它逐漸成為電子郵件、網(wǎng)頁(yè)及其他存儲(chǔ)或發(fā)送文字優(yōu)先采用的編碼方式。

—— 維基百科

UTF-8需要兼容ASCII,所以也需要有前綴碼來(lái)控制,前綴規(guī)則如下:

  • 1)如果首字節(jié)以 0 開頭,則是單字節(jié)編碼(即單個(gè)單字節(jié)碼元);

  • 2)如果首字節(jié)以 110 開頭,則是雙字節(jié)編碼(即由兩個(gè)單字節(jié)碼元所組成的雙碼元序列);

  • 3)如果首字節(jié)以 1110 開頭,則是三字節(jié)編碼(即由三個(gè)單字節(jié)碼元所組成的三碼元序列),以此類推。

理論上UTF-8變長(zhǎng)可以超過4個(gè)字節(jié),只是Unicode聯(lián)盟規(guī)范上限是10FFFF,所以UTF-8規(guī)則設(shè)計(jì)上也限制了大小。

10.5.2程序算法

用文字不太好描述算法結(jié)構(gòu),我們就直接來(lái)欣賞一下UTF-8鼻祖寫的這段解析代碼,這是Ken Thompson(B語(yǔ)言、C語(yǔ)言的作者、Unix之父)和 Rob Pike 用一個(gè)晚上寫出來(lái)的編解碼算法,代碼非常簡(jiǎn)短精煉,為了方便閱讀我加了注釋解讀。

typedefstruct

{

??intcmask; //前綴碼掩碼

??intcval;? //前綴碼

??intshift; //移動(dòng)位數(shù)

??longlmask; //Unicode值掩碼

??longlval;? //Unicode下限值

} Tab;

?

staticTab? tab[] =

{

??0x80, 0x00, 0*6, 0x7F,?????? 0,???????? /* 1 byte sequence */

??0xE0, 0xC0, 1*6, 0x7FF,????? 0x80,????? /* 2 byte sequence */

??0xF0, 0xE0, 2*6, 0xFFFF,???? 0x800,???? /* 3 byte sequence */

??0xF8, 0xF0, 3*6, 0x1FFFFF,?? 0x10000,?? /* 4 byte sequence */

??0xFC, 0xF8, 4*6, 0x3FFFFFF,? 0x200000,? /* 5 byte sequence */

??0xFE, 0xFC, 5*6, 0x7FFFFFFF, 0x4000000, /* 6 byte sequence */

??0, /* end of table */

};

?

/**

* 把一個(gè)多字節(jié)序列轉(zhuǎn)換為一個(gè)寬字符

*

* @param p 存放計(jì)算后的unicode值

* @param s 需要解析的UTF-8字節(jié)序列

* @param n 字節(jié)長(zhǎng)度

* @return 解析的字節(jié)長(zhǎng)度

*/

intmbtowc(wchar_t*p, char*s, size_tn)

{

??longl;? intc0, c, nc;? Tab *t;

??if(s == 0) return0;

??nc = 0;

??//異常校驗(yàn)(可不用關(guān)注)

??if(n <= nc) return-1;

??//c0 此處備份一下首字節(jié),后續(xù)需要用到前綴碼

??c0 = *s & 0xff;

??//l 保存 Unicode 結(jié)果

??l = c0;

??/* 遍歷tab,從單字節(jié)結(jié)構(gòu)->2字節(jié)結(jié)構(gòu)->..依次檢查找到對(duì)應(yīng)tab */

??for(t=tab; t->cmask; t++) {

????//字節(jié)數(shù)+1,字節(jié)數(shù)和tab結(jié)構(gòu)是對(duì)應(yīng)的,也就是當(dāng)nc=1時(shí) tab結(jié)構(gòu)是單字節(jié),nc=2是tab是兩字節(jié)

????nc++;

????/* 判斷前綴碼跟當(dāng)前的tab是否一致, 如果一致計(jì)算最終unicode值并返回*/

????if((c0 & t->cmask) == t->cval) {

??????//通過 & Unicode有效值掩碼,移除高位前綴碼,得到最終unicode值

??????l &= t->lmask;

??????//異常校驗(yàn)

??????if(l < t->lval) return-1;

??????//保存結(jié)果并反回

??????*p = l;

??????returnnc;

????}

????//異常校驗(yàn)

????if(n <= nc) return-1;

????//讀取下個(gè)字節(jié);如果上面判斷前綴碼不一致,說(shuō)明需要再讀取下個(gè)字節(jié)

????s++;

????//計(jì)算有效位的值,目的是去除UTF-8 編碼從第二個(gè)字節(jié)開始的高兩位10

????// 例如 s=10101111、0x80=10000000 計(jì)算結(jié)果是00101111,這樣就去除了高位前綴10

????c = (*s ^ 0x80) & 0xFF;

????//異常校驗(yàn)

????if(c & 0xC0) return-1;

????//重新計(jì)算unicode值,根據(jù)UTF-8規(guī)則c只有低 6 位有效,所以通過移位把c填入到l的低6位

????l = (l<<6) | c;

??}

??//返回異常

??return-1;

}

10.5.3容錯(cuò)性

通過上面的程序我們知道:解析過程是一個(gè)字節(jié)一個(gè)字節(jié)往下處理的,我們?cè)趥鬏斶^程中如果發(fā)生局部的字節(jié)錯(cuò)誤、丟失,或者中間有一個(gè)字節(jié)規(guī)則對(duì)不上,會(huì)不會(huì)影響整個(gè)文本的解析?

我們先來(lái)看下其他編碼的容錯(cuò)情況:從對(duì)于單字節(jié)的ASCII碼來(lái)說(shuō),丟失一個(gè)字節(jié)就丟失一個(gè)字符,并不影響后續(xù)文本的內(nèi)容,比如Hello world,丟失b2字節(jié)后內(nèi)容是Hllo world少個(gè)e而已。

我們?cè)賮?lái)看GB2312這種多字節(jié)編碼:如果丟失了b2字節(jié)那么整個(gè)文本都亂套了,這是最糟糕的,大部分多字節(jié)編碼都有類似問題,一旦出現(xiàn)錯(cuò)誤可能導(dǎo)致整個(gè)文件都需要重傳。

接下來(lái)我們看看UTF-8是如何避免這種“一顆老鼠屎壞了一鍋粥”的情況:UTF-8 的碼元序列的第一個(gè)字節(jié)指明了后面所跟字節(jié)的個(gè)數(shù),比如首字節(jié)高位是0就表示單字節(jié),110表示總共兩個(gè)字節(jié),1110表示三個(gè)字節(jié)依次類推,除首字節(jié)之外后續(xù)字節(jié)都是10開頭。所以UTF-8的前綴碼具有很強(qiáng)的魯棒性,即使丟失、增加、改變個(gè)別字節(jié)也不會(huì)導(dǎo)致后續(xù)字符全部錯(cuò)亂這樣的傳遞性、連鎖性的錯(cuò)誤問題。

十一、本文總結(jié)

看起來(lái)好像誰(shuí)都懂的字符編碼知識(shí),深入了解之后發(fā)現(xiàn)也有這么濃重的發(fā)展歷程,試想一下,如果計(jì)算機(jī)還是跟之前大型機(jī)一樣,個(gè)人計(jì)算機(jī)沒有井噴式發(fā)展起來(lái)就沒有這些字符編碼的事了,如果ASCII當(dāng)初就設(shè)計(jì)成多字節(jié)編碼,也沒有后面UNICODE什么事了。

計(jì)算機(jī)字符編碼發(fā)展歷程其實(shí)就是一個(gè)很典型的架構(gòu)設(shè)計(jì)問題。

到底好的架構(gòu)是設(shè)計(jì)出來(lái)的,還是演化出來(lái)的?

有人說(shuō)靠演化出來(lái)的:沒有設(shè)計(jì)的產(chǎn)品架構(gòu)是沒有靈魂的,發(fā)展的路上死的很快。

有人說(shuō)靠設(shè)計(jì)出來(lái)的:這是一種完美主義者,你超前設(shè)計(jì)個(gè)50年、100年等你設(shè)計(jì)出來(lái)了,說(shuō)不定公司都已經(jīng)倒閉了,有很多叫好不叫做的產(chǎn)品、架構(gòu)也比比皆是。

其實(shí):一個(gè)好的架構(gòu)是既要靠設(shè)計(jì)又要靠演化,老話說(shuō)的好三分靠設(shè)計(jì)七分靠演化,我們既要學(xué)會(huì)務(wù)實(shí),也要懂得前瞻,至少我們首先需要活下來(lái)。

十二、參考資料

[1]?Unicode中文編碼表

[2]?Every Developer Should Know About The Encoding

[3]?史上最通俗,徹底搞懂字符亂碼問題的本質(zhì)

[4]?字符編碼那點(diǎn)事:快速理解ASCII、Unicode、GBK和UTF-8

[5]?面試必考,史上最通俗大小端字節(jié)序詳解

附錄:阿里技術(shù)文章匯總

《阿里釘釘技術(shù)分享:企業(yè)級(jí)IM王者——釘釘在后端架構(gòu)上的過人之處》

《現(xiàn)代IM系統(tǒng)中聊天消息的同步和存儲(chǔ)方案探討》

《阿里技術(shù)分享:深度揭秘阿里數(shù)據(jù)庫(kù)技術(shù)方案的10年變遷史》

《阿里技術(shù)分享:阿里自研金融級(jí)數(shù)據(jù)庫(kù)OceanBase的艱辛成長(zhǎng)之路》

《來(lái)自阿里OpenIM:打造安全可靠即時(shí)通訊服務(wù)的技術(shù)實(shí)踐分享》

《釘釘——基于IM技術(shù)的新一代企業(yè)OA平臺(tái)的技術(shù)挑戰(zhàn)(視頻+PPT) [附件下載]》

《阿里技術(shù)結(jié)晶:《阿里巴巴Java開發(fā)手冊(cè)(規(guī)約)-華山版》[附件下載]》

《重磅發(fā)布:《阿里巴巴Android開發(fā)手冊(cè)(規(guī)約)》[附件下載]》

《作者談《阿里巴巴Java開發(fā)手冊(cè)(規(guī)約)》背后的故事》

《《阿里巴巴Android開發(fā)手冊(cè)(規(guī)約)》背后的故事》

《干了這碗雞湯:從理發(fā)店小弟到阿里P10技術(shù)大?!?/p>

《揭秘阿里、騰訊、華為、百度的職級(jí)和薪酬體系》

《淘寶技術(shù)分享:手淘億級(jí)移動(dòng)端接入層網(wǎng)關(guān)的技術(shù)演進(jìn)之路》

《難得干貨,揭秘支付寶的2維碼掃碼技術(shù)優(yōu)化實(shí)踐之路》

《淘寶直播技術(shù)干貨:高清、低延時(shí)的實(shí)時(shí)視頻直播技術(shù)解密》

《阿里技術(shù)分享:電商IM消息平臺(tái),在群聊、直播場(chǎng)景下的技術(shù)實(shí)踐》

《阿里技術(shù)分享:閑魚IM基于Flutter的移動(dòng)端跨端改造實(shí)踐》

《阿里IM技術(shù)分享(三):閑魚億級(jí)IM消息系統(tǒng)的架構(gòu)演進(jìn)之路》

《阿里IM技術(shù)分享(四):閑魚億級(jí)IM消息系統(tǒng)的可靠投遞優(yōu)化實(shí)踐》

《阿里IM技術(shù)分享(五):閑魚億級(jí)IM消息系統(tǒng)的及時(shí)性優(yōu)化實(shí)踐》

《阿里IM技術(shù)分享(六):閑魚億級(jí)IM消息系統(tǒng)的離線推送到達(dá)率優(yōu)化》

《阿里IM技術(shù)分享(七):閑魚IM的在線、離線聊天數(shù)據(jù)同步機(jī)制優(yōu)化實(shí)踐》

《阿里IM技術(shù)分享(八):深度解密釘釘即時(shí)消息服務(wù)DTIM的技術(shù)設(shè)計(jì)》

《阿里IM技術(shù)分享(九):深度揭密RocketMQ在釘釘IM系統(tǒng)中的應(yīng)用實(shí)踐》

(本文已同步發(fā)布于:http://www.52im.net/thread-4210-1-1.html)


史詩(shī)級(jí)計(jì)算機(jī)字符編碼知識(shí)分享,萬(wàn)字長(zhǎng)文,一文即懂!的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
砚山县| 融水| 望都县| 东源县| 固安县| 含山县| 元氏县| 富蕴县| 承德县| 赤峰市| 普兰店市| 江口县| 尼木县| 西贡区| 萍乡市| 婺源县| 尚志市| 前郭尔| 扎赉特旗| 岢岚县| 乌鲁木齐县| 南木林县| 宁晋县| 北宁市| 河曲县| 米脂县| 察隅县| 怀化市| 新建县| 日照市| 武强县| 万源市| 辰溪县| 巴里| 新绛县| 楚雄市| 安仁县| 大渡口区| 临洮县| 上蔡县| 敦化市|