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ā)不可收拾钾虐。
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
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)化為字符。
- 這種格式的好處在于勃痴,讀取效率尤其高谒所。計(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解決了常用字符(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ī)則如下
-
U+0000
-U+FFFF
使用兩個(gè)字節(jié)直接表示味榛。 -
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的示例
而讀取時(shí)的轉(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í)資料后加以自己的理解散休,整理成文