優(yōu)點(diǎn)
UTF-8
- 兼容 ASCII
- 能適應(yīng)許多 C 庫中的 \0 結(jié)尾慣例
- 沒有字節(jié)序問題
- 良好的多語種支持(相對(duì) GBK 等跟語種綁定的編碼方式)
- 以英文和西文符號(hào)比較多的場(chǎng)景下(例如 HTML/XML)烹吵,編碼較短
- 由于是變長(zhǎng),字符空間足夠大,未來 Unicode 新標(biāo)準(zhǔn)收錄更多字符,UTF-8 也能妥妥的兼容喇潘,因此不會(huì)再出現(xiàn) UTF-16 那樣的尷尬
- 不存在大小端字節(jié)序問題戒劫,信息交換時(shí)非常便捷
- 容錯(cuò)性高,局部的字節(jié)錯(cuò)誤(丟失耘沼、增加韧衣、改變)不會(huì)導(dǎo)致連鎖性的錯(cuò)誤盅藻,因?yàn)?UTF-8 的字符邊界很容易檢測(cè)出來购桑,這是一個(gè)巨大的優(yōu)點(diǎn)(正是為了實(shí)現(xiàn)這一點(diǎn),咱們中日韓人民不得不忍受 3 字節(jié) 1 個(gè)字符的苦日子)
UTF-16(應(yīng)該不算優(yōu)點(diǎn))
- 最流行的操作系統(tǒng)和 UI framework 的內(nèi)部字符串表達(dá)都是 UTF-16
- Windows API 的 Wide Char 表達(dá)是 UTF-16: Unicode (Windows), L"" 表示是轉(zhuǎn)換為 wide char氏淑。
- Cocoa 的 NSString 和 Core Foundation 的 CFString 內(nèi)部表達(dá)都是 UTF-16其兴,所以其實(shí) OS X 和 iOS 內(nèi)部處理都用的是 UTF-16。
- Java String 的內(nèi)部表達(dá)是 UTF-16夸政,所以大量跨平臺(tái)程序和 Android 程序其實(shí)內(nèi)部也在用 UTF-16。
- 在計(jì)算字符串長(zhǎng)度榴徐、執(zhí)行索引操作時(shí)速度很快守问。
注:但是UTF-16也是變長(zhǎng)的,Unicode擴(kuò)展到9萬多以后坑资,也要通過變長(zhǎng)來支持了耗帕。
具體原因參照知乎回答:
編程語言的字符編碼選擇UTF-8和UTF-16的優(yōu)缺點(diǎn)?
UTF-32
- 定長(zhǎng)編碼袱贮,utf32 表示任何字符都用 4 字節(jié)仿便,讀到內(nèi)存中是個(gè)均勻的整形數(shù)組,于是我們可以很方便地隨機(jī)訪問任何一個(gè)字符
- 由于是定長(zhǎng)攒巍,索引比變長(zhǎng)的要快嗽仪,你想訪問一個(gè)字符串中的第 n 個(gè)字符,utf32 直接偏移 n 個(gè)整形距離即可柒莉,utf8 得從第一個(gè)字節(jié)一個(gè)字一個(gè)字地往后蹦闻坚,非常蛋疼。
補(bǔ)充:
UTF 32 也不想理想中那么方便索引兢孝,主要是 emoji 的鍋窿凤,舉兩個(gè)例子:一、Emoji 里面的國旗其實(shí)由兩個(gè)字符組成跨蟹,稱為 region indicator雳殊,每個(gè)字符是一個(gè) region indicator symbol letter,從 A 到 Z窗轩,U+1F1E6 到 U+1F1FF夯秃。比如說法國國旗就是用 FR 的對(duì)應(yīng) region indicator symbol letter 來表示的。Swift 的 String 自稱有較好的 Unicode 支持痢艺,但對(duì)這樣的字符的長(zhǎng)度目前給的還是 2(Unicode 8.0 標(biāo)準(zhǔn))寝并,而實(shí)際上 Unicode 9.0 已經(jīng)要求把它們看作一個(gè)字符了。二腹备、為了政治正確衬潦,人們引入了帶膚色的 emoji 表情,它們是由普通表情和一個(gè)代表顏色的 emoji 字符組成植酥。于是乎镀岛,如果寫編輯器的話弦牡,不管怎么樣都要 O(n) 來計(jì)算可見字符的長(zhǎng)度的(這還沒有考慮韓語那種三個(gè)字符疊成一個(gè)字符的情況),所以前端們很可憐的漂羊。
參見 劉閩晟 回答驾锰,鏈接
缺點(diǎn)
UTF-8
- 文化上的不平衡——對(duì)于歐美地區(qū)一些以英語為母語的國家 UTF-8 簡(jiǎn)直是太棒了,因?yàn)樗?ASCII 一樣走越,一個(gè)字符只占一個(gè)字節(jié)椭豫,沒有任何額外的存儲(chǔ)負(fù)擔(dān);但是對(duì)于中日韓等國家來說旨指,UTF-8 實(shí)在是太冗余赏酥,一個(gè)字符竟然要占用 3 個(gè)字節(jié),存儲(chǔ)和傳輸?shù)男什坏珱]有提升谆构,反而下降了裸扶。所以歐美人民常常毫不猶豫的采用 UTF-8,而我們卻老是要猶豫一會(huì)兒搬素。
- 變長(zhǎng)字節(jié)表示帶來的效率問題——大家對(duì) UTF-8 疑慮重重的一個(gè)問題就是在于其因?yàn)槭亲冮L(zhǎng)字節(jié)表示呵晨,因此無論是計(jì)算字符數(shù),還是執(zhí)行索引操作效率都不高熬尺。為了解決這個(gè)問題摸屠,常常會(huì)考慮把 UTF-8 先轉(zhuǎn)換為 UTF-16 或者 UTF-32 后再操作,操作完畢后再轉(zhuǎn)換回去粱哼。而這顯然是一種性能負(fù)擔(dān)餐塘。
UTF-16
- UTF-16 能表示的字符數(shù)有 6 萬多,看起來很多皂吮,但是實(shí)際上目前 Unicode 5.0 收錄的字符已經(jīng)達(dá)到 99024 個(gè)字符戒傻,早已超過 UTF-16 的存儲(chǔ)范圍;這直接導(dǎo)致 UTF-16 地位頗為尷尬——如果誰還在想著只要使用 UTF-16 就可以高枕無憂的話蜂筹,恐怕要失望了需纳。
- UTF-16 存在大小端字節(jié)序問題,這個(gè)問題在進(jìn)行信息交換時(shí)特別突出——如果字節(jié)序未協(xié)商好艺挪,將導(dǎo)致亂碼不翩;如果協(xié)商好,但是雙方一個(gè)采用大端一個(gè)采用小端麻裳,則必然有一方要進(jìn)行大小端轉(zhuǎn)換口蝠,性能損失不可避免(大小端問題其實(shí)不像看起來那么簡(jiǎn)單,有時(shí)會(huì)涉及硬件津坑、操作系統(tǒng)妙蔗、上層軟件多個(gè)層次,可能會(huì)進(jìn)行多次轉(zhuǎn)換)疆瑰。
- 另外眉反,容錯(cuò)性低有時(shí)候也是一大問題——局部的字節(jié)錯(cuò)誤昙啄,特別是丟失或增加可能導(dǎo)致所有后續(xù)字符全部錯(cuò)亂,錯(cuò)亂后要想恢復(fù)寸五,可能很簡(jiǎn)單梳凛,也可能會(huì)非常困難。(這一點(diǎn)在日常生活里大家感覺似乎無關(guān)緊要梳杏,但是在很多特殊環(huán)境下卻是巨大的缺陷)韧拒。
該如何選擇
簡(jiǎn)要回答:
UTF-8,用于存儲(chǔ)及傳輸
UTF-32十性,用于程序內(nèi)存中
原因:
- UTF-8靈活叛溢,在互聯(lián)網(wǎng)通信中被編碼影響小,兼容性強(qiáng)烁试。
- UTF-32定長(zhǎng),在內(nèi)存中程序處理優(yōu)秀拢肆,查詢快减响。
因?yàn)闊o論是 UTF-8 和 UTF-16/32 都各有優(yōu)缺點(diǎn),因此選擇的時(shí)候應(yīng)當(dāng)立足于實(shí)際的應(yīng)用場(chǎng)景郭怪。例如在我的習(xí)慣中支示,存儲(chǔ)在磁盤上或進(jìn)行網(wǎng)絡(luò)交換時(shí)都會(huì)采用 UTF-8,而在程序內(nèi)部進(jìn)行處理時(shí)則轉(zhuǎn)換為 UTF-16/32鄙才。對(duì)于大多數(shù)簡(jiǎn)單的程序來說颂鸿,這樣做既可以保證信息交換時(shí)容易實(shí)現(xiàn)相互兼容,同時(shí)在內(nèi)部處理時(shí)會(huì)比較簡(jiǎn)單攒庵,性能也還算不錯(cuò)嘴纺。(基本上只要你的程序不是 I/O 密集型的都可以這么干,當(dāng)然這只是我粗淺的認(rèn)識(shí)范圍內(nèi)的經(jīng)驗(yàn)浓冒,很可能會(huì)被無情的反駁)栽渴。
整理自:
知乎 - 為什么 UTF-8 編碼比 UTF-16 編碼應(yīng)用更廣泛?
參與回答:
林建入- 回答