UTF-8, UTF-16與UTF-32的傻瓜式理解

御岳山紅葉眺望

UTF是什么的簡寫

UTF是 Unicode* Transformation Format 的簡寫枉侧。直譯就是Unicode的轉(zhuǎn)換格式。
(* U同時(shí)也是UCS的簡寫,UCS和Unicode是兩個(gè)組織訂立的標(biāo)準(zhǔn)州藕,但是碼表基本兼容束世,在此略過不提)
UTF-8, UTF16, UTF-32分別對應(yīng)8bit, 16bit, 32bit長度的轉(zhuǎn)換格式。在下文詳細(xì)描述床玻。

什么是Unicode

對計(jì)算機(jī)而言毁涉,什么漢字偏旁部首,英文字母锈死,日語假名那都是不存在的贫堰。大千世界的紛繁復(fù)雜到了計(jì)算機(jī)里最終都化成了0和1組成的二進(jìn)制數(shù)。
那怎么讓計(jì)算機(jī)看懂人類用的字符呢待牵?很簡單严嗜,把字符都定義成二進(jìn)制數(shù)就行了,一個(gè)字符一個(gè)數(shù)洲敢,一個(gè)蘿卜一個(gè)坑,簡單易懂茄蚯。

ASCII

計(jì)算機(jī)發(fā)展早期大多采用ASCII編碼压彭。其使用一個(gè)字節(jié),即8位二進(jìn)制數(shù)來表示字符渗常。
ASCII的起始位為0壮不,可以表示27即128個(gè)字符。這些字符包含了0-9的數(shù)字皱碘,各種常用符號(hào)询一,大小寫英文字母以及一些控制符等。
如字符a對應(yīng)的ASCII編碼為0b01100001或者0x61
(* 0b代表二進(jìn)制癌椿,0x代表十六進(jìn)制健蕊,下同)
或者以我們常用的十進(jìn)制為編號(hào)97

ASCII起源于電報(bào)時(shí)代踢俄,27即128個(gè)字符已足以滿足當(dāng)時(shí)需求缩功。直到1970年代8位處理器開始普及,字節(jié)(Byte)的單位也由4位都办,6位等統(tǒng)一為8位二進(jìn)制數(shù)(8bit)并沿用至今嫡锌。ASCII在8位二進(jìn)制數(shù)中首位置0。后來也發(fā)展出extended ASCII編碼琳钉,對首位為1的編碼定義势木,充分利用了一個(gè)字節(jié)256個(gè)編碼。但即便如此256個(gè)編碼也不可能滿足全世界對字符編碼的需求歌懒。

隨著計(jì)算機(jī)技術(shù)的高速發(fā)展與普及啦桌,各地都發(fā)展出了各自的編碼標(biāo)準(zhǔn),以滿足在計(jì)算機(jī)上顯示歼培,處理本國語言的需求震蒋。然而一時(shí)之間標(biāo)準(zhǔn)頻出茸塞,彼此之間又多不兼容,導(dǎo)致亂碼叢生查剖,一發(fā)不可收拾钾虐。


把Big5標(biāo)準(zhǔn)下的曹操用GB標(biāo)準(zhǔn)打開就成了變巨,玩過光榮的曹操傳和三國志(繁體版)的朋友應(yīng)該很熟悉
Unicode

這時(shí)對一個(gè)全球通用的字符編碼標(biāo)準(zhǔn)的需求越來越高笋庄,而Unicode就是為此而誕生效扫。
Unicode的解釋可以參照wikipedia。以下摘自wiki-Unicode詞條

Unicode(中文:萬國碼直砂、國際碼菌仁、統(tǒng)一碼、單一碼)是計(jì)算機(jī)科學(xué)領(lǐng)域里的一項(xiàng)業(yè)界標(biāo)準(zhǔn)静暂。它對世界上大部分的文字系統(tǒng)進(jìn)行了整理济丘、編碼,使得電腦可以用更為簡單的方式來呈現(xiàn)和處理文字洽蛀。
Unicode 伴隨著通用字符集的標(biāo)準(zhǔn)而發(fā)展摹迷,同時(shí)也以書本的形式[1]對外發(fā)表。Unicode 至今仍在不斷增修郊供,每個(gè)新版本都加入更多新的字符峡碉。當(dāng)前最新的版本為2019年5月公布的12.1.0[2],已經(jīng)收錄超過13萬個(gè)字符(第十萬個(gè)字符在2005年獲采納)驮审。Unicode涵蓋的數(shù)據(jù)除了視覺上的字形鲫寄、編碼方法、標(biāo)準(zhǔn)的字符編碼外疯淫,還包含了字符特性地来,如大小寫字母。

簡單說來Unicode就是一個(gè)包含世界上大多數(shù)國家的文字/符號(hào)的編碼標(biāo)準(zhǔn)熙掺。它給每個(gè)字符一個(gè)編號(hào)靠抑,形成了一個(gè)龐大的字符集。

Unicode的表示

Unicode拓展自ASCII适掰,因此上文的a在Unicode中的編碼不變颂碧,為U+0061
Unicode編碼為U+加上至少4位十六進(jìn)制數(shù)字的形式表示类浪。例如這個(gè)漢字的Unicode為U+6211载城,的Unicode為U+6c49。最新的Unicode12.1版本中除去tag费就,被注冊的最大的編碼為中日韓兼容表意文字诉瓦,為U+2F9FF
https://unicode-table.com/cn/#2F9FF

U+2F9FF

Unicode Transformation Format (UTF)

如上文所述,一個(gè)字節(jié)8位睬澡,至多表示28=256個(gè)編碼固额。而Unicode以收錄十多萬個(gè)字符,顯然用一個(gè)字節(jié)無法表示所有的Unicode編碼煞聪。
兩個(gè)字節(jié)16位斗躏,至多表示216=65536個(gè)編碼。顯然也不足夠昔脯。
再翻個(gè)倍四個(gè)字節(jié)32位啄糙,就能表示232=4294967296個(gè)編碼。所以Unicode通常使用1-4個(gè)字節(jié)來表示字符云稚。
計(jì)算機(jī)很蠢隧饼,看到一大堆數(shù)據(jù)便直接一整套全都讀取進(jìn)去。如何分割字節(jié)静陈,如何把編碼轉(zhuǎn)化成字符燕雁,必須由人來告訴它。
UTF即是告訴計(jì)算機(jī)如何存儲(chǔ)讀取字符的一種格式鲸拥。

UTF-32

上文提到贵白,4個(gè)字節(jié)足以表示任何Unicode,因此UTF-32就采用每個(gè)字符4個(gè)字節(jié)的儲(chǔ)存形式(4個(gè)字節(jié)為32位崩泡,因此是UTF-32)。
UTF-32格式下猬膨,每個(gè)字符會(huì)讀取4個(gè)字節(jié)角撞,然后按標(biāo)準(zhǔn)轉(zhuǎn)化為字符。


UTF-32每次讀取4個(gè)字節(jié)
  • 這種格式的好處在于勃痴,讀取效率尤其高谒所。計(jì)算機(jī)只管4個(gè)字節(jié)4個(gè)字節(jié)地讀,不需要考慮其他沛申。
  • 而缺點(diǎn)就在于劣领,空間占用率過大。
    對于英語國家而言铁材,常用的字符已包含在ASCII中尖淘,也就是說一個(gè)字節(jié)就能滿足大多數(shù)使用場景。而UTF-32的格式下著觉,即便是ASCII中的字符村生,也要占用4個(gè)字節(jié),是原來的4倍饼丘。
    (4倍趁桃,那是什么概念!!四舍五入就是一個(gè)億拔啦 S推 !)

考慮到UTF-32造成的浪費(fèi)蟀苛,一般情況下UTF-8和UTF-16才是主流選擇益咬。

UTF-8

UTF-8是最常用的一種Unicode轉(zhuǎn)換格式。也是最靈活的一種格式屹逛。
UTF-8解決了UTF-32占用空間過大的問題础废。8即是8位,代表著讀取單位為8bit罕模,即1個(gè)字節(jié)评腺。
ASCII的字符只用這1個(gè)字節(jié)便可以轉(zhuǎn)換,而其他字符則由多個(gè)字節(jié)組成淑掌。
由于采用了這種組合式的做法蒿讥。UTF-8編碼的每個(gè)字節(jié)需要用字節(jié)開頭的幾位(bit)來告訴計(jì)算機(jī)一些信息,比如這個(gè)字節(jié)是某個(gè)字符的首字節(jié)抛腕,由多少個(gè)字節(jié)組成芋绸,亦或者這個(gè)字節(jié)是別的字符的后續(xù)。
其具體規(guī)則如下担敌,參考自https://stackoverflow.com/a/33349765

Binary Hex Comments
0xxxxxxx 0x00..0x7F Only byte of a 1-byte character encoding
單字節(jié)字符
10xxxxxx 0x80..0xBF Continuation byte: one of 1-3 bytes following the first
多字節(jié)字符的后續(xù)字節(jié)
110xxxxx 0xC0..0xDF First byte of a 2-byte character encoding
雙字節(jié)字符的首字節(jié)
1110xxxx 0xE0..0xEF First byte of a 3-byte character encoding
三字節(jié)字符的首字節(jié)
11110xxx 0xF0..0xF7 First byte of a 4-byte character encoding
四字節(jié)字符的首字節(jié)
  • 單字節(jié)字符首位取0
  • n字節(jié)字符的首字節(jié)前n位取1摔敛,n+1位取0
  • 多字節(jié)字符的后續(xù)字節(jié)前兩位取10
UTF-8的轉(zhuǎn)換方法

UTF-8解決了常用字符(1-3字節(jié))在UTF-32下占用空間過大的問題。但其缺點(diǎn)也同樣存在全封,

  • 其一马昙,相對于UTF-32,UTF-8的讀取效率有所降低刹悴,畢竟需要讀取標(biāo)識(shí)位并加以轉(zhuǎn)化行楞。
    相比直接讀取4個(gè)字節(jié),會(huì)消耗一小部分性能土匀。
  • 其二子房,Unicode中漢字區(qū)間為0x4E00→0x9FA5,在UTF-8下都需要占用三個(gè)字節(jié)就轧,如上圖字证杭,UTF-8下編碼為E58F8B,但其Unicode編碼其實(shí)是U+53CB妒御,理論上只使用兩個(gè)字節(jié)就能表示躯砰,也存在著空間浪費(fèi)的情況。
    美國人是開心了携丁,中國人民不干了
UTF-16

UTF-16是一種折衷的方案琢歇,UTF-16使用2或者4個(gè)字節(jié)來表示字符兰怠。
U+0000-U+FFFF的字符均用2個(gè)字節(jié)表示,而此范圍以外的字符用4個(gè)字節(jié)表示李茫。
由于常用字符以及主要國家的文字字符基本都包含在這個(gè)范圍中揭保,所以在絕大多數(shù)情況下字符都只需2個(gè)字節(jié),通用性很高魄宏。
世界人民皆大歡喜

UTF-16可以表示U+0000-U+10FFFF的編碼區(qū)間秸侣,有一千多萬個(gè)編碼,在現(xiàn)階段足夠使用宠互。
其編碼規(guī)則如下

  1. U+0000 - U+FFFF
    使用兩個(gè)字節(jié)直接表示味榛。
  2. U+10000 - U+10FFFF
    a. 將Unicode編碼減去0x10000(因?yàn)?code>0x10000以下的編碼已包含在1中),得到的編碼的區(qū)間是0x00000-0xFFFFF(最大為5位16進(jìn)制數(shù)予跌,即20位二進(jìn)制數(shù)搏色,20bit)。
    b. 將得到的編碼分為兩部分券册,每一部分為10位二進(jìn)制數(shù)(10bit)频轿。
    c. 在高位的10bit前補(bǔ)上6位的標(biāo)識(shí)110110,即加上0b 1101 1000 0000 0000=0xD800烁焙,這個(gè)0xD800也稱為前導(dǎo)代理(lead surrogates)航邢。
    d. 在低位的10bit前補(bǔ)上6位的標(biāo)識(shí)110111,即加上0xDC00骄蝇,這個(gè)0xDC00也稱為后尾代理(trail surrogates)膳殷。

可參照wiki的示例

UTF-16 wiki示例的截圖

而讀取時(shí)的轉(zhuǎn)化方法如下圖所示


UTF-16讀取2或4個(gè)字節(jié),并加以轉(zhuǎn)換

UTF-16作為一個(gè)折衷方案九火,使常用字符都能用2個(gè)字節(jié)表示赚窃,這是其最大的優(yōu)點(diǎn)。
而由于UTF-16使用了前導(dǎo)/后導(dǎo)代理吃既,導(dǎo)致以11011開頭的Unicode編碼無法使用(會(huì)導(dǎo)致UTF-16格式下無法辨識(shí)),因此Unicode規(guī)定U+D800 - U+DFFF區(qū)間內(nèi)的編碼空置跨细。

BOM(字節(jié)順序標(biāo)記)

由于多種字符轉(zhuǎn)化格式的存在鹦倚,一個(gè)文本文件通常需要在其開頭注明該文件的格式。
這種文件開始處的標(biāo)記就稱為byte-order mark冀惭,BOM震叙。
BOM的示例直接從wiki拉過來
https://en.wikipedia.org/wiki/Byte_order_mark

編碼 表示(十六進(jìn)制 表示(十進(jìn)制
UTF-8 EF BB BF 239 187 191
UTF-16(大端序) FE FF 254 255
UTF-16(小端序) FF FE 255 254
UTF-32(大端序) 00 00 FE FF 0 0 254 255
UTF-32(小端序) FF FE 00 00 255 254 0 0
UTF-7 2B 2F 76
和以下的一個(gè)字節(jié):
[ 38 | 39 | 2B | 2F ]
43 47 118
和以下的一個(gè)字節(jié):
[ 56 | 57 | 43 | 47 \]
UTF-1 F7 64 4C 247 100 76
UTF-EBCDIC DD 73 66 73 221 115 102 115
Unicode標(biāo)準(zhǔn)壓縮方案 0E FE FF 14 254 255
BOCU-1 FB EE 28 及可能跟隨著FF 251 238 40 及可能跟隨著255
GB-18030 84 31 95 33 132 49 149 51

以上為一個(gè)半路出家的碼農(nóng),遍搜學(xué)習(xí)資料后加以自己的理解散休,整理成文

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末媒楼,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子戚丸,更是在濱河造成了極大的恐慌划址,老刑警劉巖扔嵌,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異夺颤,居然都是意外死亡痢缎,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進(jìn)店門世澜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來独旷,“玉大人,你說我怎么就攤上這事寥裂∏锻荩” “怎么了?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵封恰,是天一觀的道長麻养。 經(jīng)常有香客問我,道長俭驮,這世上最難降的妖魔是什么回溺? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮混萝,結(jié)果婚禮上遗遵,老公的妹妹穿的比我還像新娘。我一直安慰自己逸嘀,他們只是感情好车要,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著崭倘,像睡著了一般翼岁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上司光,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天琅坡,我揣著相機(jī)與錄音,去河邊找鬼残家。 笑死榆俺,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的坞淮。 我是一名探鬼主播茴晋,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼回窘!你這毒婦竟也來了诺擅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤啡直,失蹤者是張志新(化名)和其女友劉穎烁涌,沒想到半個(gè)月后苍碟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡烹玉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年驰怎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片二打。...
    茶點(diǎn)故事閱讀 39,764評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡县忌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出继效,到底是詐尸還是另有隱情症杏,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布瑞信,位于F島的核電站厉颤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏凡简。R本人自食惡果不足惜逼友,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望秤涩。 院中可真熱鬧帜乞,春花似錦、人聲如沸筐眷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽匀谣。三九已至照棋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間武翎,已是汗流浹背烈炭。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留宝恶,地道東北人符隙。 一個(gè)月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像卑惜,于是被迫代替她去往敵國和親膏执。 傳聞我的和親對象是個(gè)殘疾皇子驻售,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評論 2 354