談?wù)勛址幋a

一直覺得:一個(gè)合格的程序員必須要了解清楚編碼。

程序員的工作中很頻繁的一個(gè)場景是:啊啊,又(中文)亂碼了输硝,怎么弄, 然后搜索引擎搜了后總是一頓亂試程梦,可能當(dāng)時(shí)解決了点把,下次遇到問題,又不知道怎么辦屿附,一直沒有深入理解其原理郎逃。

先思考以下幾個(gè)問題:

  • 為什么要用十六進(jìn)制 (0x7f) 來標(biāo)識(shí)字節(jié)?
  • 計(jì)算機(jī)怎么讀韧Ψ荨(文本/二進(jìn)制)數(shù)據(jù)并解碼并顯示褒翰?
  • 經(jīng)常遇到中文亂碼是怎么造成的?
  • Unicode 與 UTF-8 是什么關(guān)系匀泊?分別解決了什么問題优训?
  • 經(jīng)常看到 (不)帶 BOM 的 UTF-8, 其中 BOM 是什么探赫?

從本文下面的一些分析來一一解答型宙。

序言

計(jì)算機(jī)里面存儲(chǔ)的都是二進(jìn)制序列 0101010,思考怎么把它通過一套規(guī)則與現(xiàn)實(shí)世界的字符對應(yīng)起來伦吠,就出現(xiàn)了各種字符集,字符編碼規(guī)范魂拦。

為什么要用十六進(jìn)制毛仪?

很簡單,為了簡潔芯勘,方便箱靴。二進(jìn)制 0101 列起來太多,且浪費(fèi)存儲(chǔ)空間荷愕。
1byte = 8bit = 2hex 一個(gè)字節(jié) 需要8位二進(jìn)制標(biāo)識(shí)衡怀,而只需要2個(gè)十六進(jìn)制即可。
我們經(jīng)常能看到的16進(jìn)制通常以 0x \x 開頭為標(biāo)識(shí)安疗。兩個(gè)十六進(jìn)制為一個(gè)字節(jié)抛杨。下文的很多表示都用的十六進(jìn)制。

已編碼字符集(CCS)

從抽象字符清單到非負(fù)整數(shù)(范圍不必連續(xù))的映射荐类。該整數(shù)稱為抽象字符被賦予的碼點(diǎn)(code point怖现,或稱碼位code position),該字符則稱為已編碼字符。注意屈嗤,碼點(diǎn)并非比特或字節(jié)潘拨,因此與計(jì)算機(jī)表示無關(guān)。碼點(diǎn)的取值范圍由編碼標(biāo)準(zhǔn)限定饶号,該范圍稱為編碼空間(code space)铁追。在一個(gè)標(biāo)準(zhǔn)中,已編碼字符集也稱為字符編碼茫船、已編碼字符清單琅束、字符集定義或碼頁(code page)。

單字節(jié)編碼方案

ASCII

最開始 ASCII (American Standard Code for Information Interchange)美國信息交換標(biāo)準(zhǔn)代碼透硝,是基于拉丁字母 的一套電腦編碼系統(tǒng)狰闪。它主要用于顯示現(xiàn)代英語。

ASCII 使用一個(gè)字節(jié) 8 bit (實(shí)際上是7 bit) 定義了 2^7 = 128 個(gè)字符濒生,如下
二進(jìn)制:0000 0000 - 0111 1111
十進(jìn)制: 0 - 127
十六進(jìn)制:0x00 - 0x7F

ISO-8859-1

ISO-8859-1 (又稱Latin-1或“西歐語言”) 擴(kuò)展了 ASCII 因?yàn)槔碚撋?8 bit 可以表示 2^8-1 = 255 個(gè)字符埋泵。
它以ASCII為基礎(chǔ),在空置的 0xA0-0xFF 的范圍內(nèi)罪治,加入96個(gè)字母及符號(hào)丽声。

它的字符集如下:
ISO-8859-1 字符集表

可以看到 0x7F、0x80-0x9F 在此字符集中未有定義觉义。例如歐元符號(hào)(0x80 (gbk-cp936))
然后偉大的漢字沒有對應(yīng)的編碼雁社,后來國家自己搞了一套編碼擴(kuò)展了 ASCII 。 例如 GB2312 到后來的 GBK 等晒骇。

多字節(jié)編碼

由于單字節(jié)能表示的字符太少霉撵,且同時(shí)也需要與 ASCII 編碼保持兼容,所以不同國家和地區(qū)紛紛在 ASCII 基礎(chǔ)上制定自己的字符集洪囤。這些字符集使用大于0x80的編碼作為一個(gè)前導(dǎo)字節(jié)徒坡,前導(dǎo)字節(jié)與緊跟其后的第二(甚至第三)個(gè)字節(jié)一起作為單個(gè)字符的實(shí)際編碼;

多字節(jié)編碼的解析

單字節(jié)編碼解析很簡單瘤缩,一個(gè)字節(jié)一個(gè)字節(jié)的讀即可喇完。但是多字節(jié)編碼涉及到字節(jié)解析問題。例如 GBK 使用兩個(gè)字節(jié)編碼剥啤,在遇到大于 0x80 的讀取雙字節(jié)锦溪,小于 0x80 開頭的即為 ASCII 單字節(jié)。(類似于用前綴進(jìn)行區(qū)分)

GBK

GBK 兼容了 ASCII府怯,漢字采用雙字節(jié)編碼刻诊。總體上說第一字節(jié)的范圍是81–FE(也就是不含80和FF)富腊,第二字節(jié)的一部分領(lǐng)域在40–7E坏逢,其他領(lǐng)域在80–FE。
單字節(jié) (0xxx xxxxx)
雙字節(jié) (1xxxx xxxx xxxx xxxx)

需要注意的是:GBK 編碼不支持歐元符號(hào)"€",Windows CP936 碼頁使用 0x80 表示歐元是整,GB18030 編碼則使用0xA2E3表示歐元肖揣。

Unicode 與 UTF-8

Unicode 是一套國際統(tǒng)一標(biāo)準(zhǔn)的字符集(規(guī)范),世界上每一個(gè)可見字符都在 Unicode 里面有一一映射關(guān)系浮入。
每個(gè)字符對應(yīng) Unicode 里面的一個(gè)碼點(diǎn)龙优。
Unicode 使用四個(gè)字節(jié),定義了每個(gè)字符的碼點(diǎn)事秀。然而存儲(chǔ)數(shù)據(jù)如果全部使用 Unicode 會(huì)造成很大的浪費(fèi)彤断。所以出現(xiàn)了 UTF-8 之類的編碼格式。UTF (Unicode Translation Format, UTF )翻譯下就是 Unicode 轉(zhuǎn)換格式易迹。定義了如果將 Unicode 與字節(jié)(二進(jìn)制序列)一一映射宰衙。

UTF-8

UTF-8 是一種針對 Unicode 的可變寬度字符編碼,可表示 Unicode 標(biāo)準(zhǔn)中的任何字符睹欲。UTF-8已逐漸成為電子郵件供炼、網(wǎng)頁及其他存儲(chǔ)傳輸文字的應(yīng)用中,優(yōu)先采用的編碼窘疮〈撸互聯(lián)網(wǎng)工程工作小組(IETF)要求所有互聯(lián)網(wǎng)協(xié)議都必須支持 UTF-8 編碼。

UTF-8 使用1-4個(gè)字節(jié)為每個(gè)字符編碼闸衫,其規(guī)則如下(x表示可用編碼的比特位):
UTF-8 是定義了 Unicode 映射的字符在計(jì)算機(jī)上如何存儲(chǔ)涛贯。

Unicode碼點(diǎn)(Hex) UTF-8序列(Bin) 字節(jié)數(shù)
0000 - 007F 0xxxxxxx 1
0080 - 07FF 110xxxxx 10xxxxxx 2
0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx 3
10000~10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 4

BOM 是什么?

UTF-8 以字節(jié)為編碼單元蔚出,沒有字節(jié)序的問題弟翘。UTF-16 以兩個(gè)字節(jié)為編碼單元,在解釋一個(gè) UTF-16文本前骄酗,首先要弄清楚每個(gè)編碼單元的字節(jié)序衅胀。例如“奎”的Unicode編碼是594E, “乙”的Unicode編碼是4E59纯路。如果我們收到UTF-16字節(jié)流“594E”持际,那么這是“奎” 還 是“乙”? Unicode 規(guī)范中推薦的標(biāo)記字節(jié)順序的方法是 BOM, Unicode 將幾個(gè)特定的碼點(diǎn) 例如 U+FEFF 的字符定義為字節(jié)順序標(biāo)記(Byte Order Mark, BOM)

不同的編碼方案對零寬不換行字符的解析如下:

編碼方案 大字節(jié)序(Hex) 小字節(jié)序(Hex)
UTF-8 EF BB BF EF BB BF
UTF-16 Fe FF FF Fe
UTF-32 00 00 Fe FF FF Fe 00 00

UTF-16 和 UTF-32 編碼默認(rèn)為大字節(jié)序站故。UTF-8 以字節(jié)為編碼單元,沒有字節(jié)序問題鲫趁,BOM 只用于表明其編碼格式(signature)*确沸。
Unicode標(biāo)準(zhǔn)并未要求或建議UTF-8編碼使用BOM,但確實(shí)允許BOM出現(xiàn)在文件開頭募闲。帶有BOM的Unicode文件有時(shí)會(huì)帶來一些問題:

  • Linux/UNIX系統(tǒng)未使用BOM步脓,因?yàn)樗鼤?huì)破壞現(xiàn)有ASCII文件的語法約定。
  • 某些編輯器不會(huì)添加BOM,或者可以選擇是否添加BOM靴患。
  • 某些語法分析器可以處理字符串常量或注釋中的UTF-8仍侥,但無法分析文件開頭的BOM。
  • 某些程序在文件開頭插入前導(dǎo)字符來聲明文件類型等信息鸳君,這與BOM的用途沖突农渊。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市或颊,隨后出現(xiàn)的幾起案子砸紊,更是在濱河造成了極大的恐慌,老刑警劉巖囱挑,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件醉顽,死亡現(xiàn)場離奇詭異,居然都是意外死亡平挑,警方通過查閱死者的電腦和手機(jī)游添,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弹惦,“玉大人否淤,你說我怎么就攤上這事√囊” “怎么了石抡?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長助泽。 經(jīng)常有香客問我啰扛,道長,這世上最難降的妖魔是什么嗡贺? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任隐解,我火速辦了婚禮,結(jié)果婚禮上诫睬,老公的妹妹穿的比我還像新娘煞茫。我一直安慰自己,他們只是感情好摄凡,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布续徽。 她就那樣靜靜地躺著,像睡著了一般亲澡。 火紅的嫁衣襯著肌膚如雪钦扭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天床绪,我揣著相機(jī)與錄音客情,去河邊找鬼其弊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛膀斋,可吹牛的內(nèi)容都是我干的梭伐。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼概页,長吁一口氣:“原來是場噩夢啊……” “哼籽御!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起惰匙,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤技掏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后项鬼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哑梳,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年绘盟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鸠真。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡龄毡,死狀恐怖吠卷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情沦零,我是刑警寧澤祭隔,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站路操,受9級(jí)特大地震影響疾渴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜屯仗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一搞坝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧魁袜,春花似錦桩撮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至垮卓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間师幕,已是汗流浹背粟按。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工诬滩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人灭将。 一個(gè)月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓疼鸟,卻偏偏與公主長得像,于是被迫代替她去往敵國和親庙曙。 傳聞我的和親對象是個(gè)殘疾皇子空镜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 字符集和編碼簡介 在編程中常常可以見到各種字符集和編碼捌朴,包括ASCII,MBCS,Unicode等字符集吴攒。確切的說...
    蘭山小亭閱讀 8,453評論 0 13
  • 編碼問題一直困擾著開發(fā)人員,尤其在 Java 中更加明顯砂蔽,因?yàn)?Java 是跨平臺(tái)語言洼怔,不同平臺(tái)之間編碼之間的切換...
    x360閱讀 2,465評論 1 20
  • 今日我的感恩日記是陪弟弟去逛商場,去龍華文化廣場左驾,買水果和吃的給他們镣隶,讓他們吃更好。 晚上和娜娜诡右,銀霞安岂,云兒,小慧...
    云兒飛1990閱讀 88評論 0 0
  • 著名的“五朵花”理論――簡而言之帆吻,人就像種子域那,需要陽光、水桅锄、空氣琉雳,才能綻放自己的美麗,開花結(jié)果友瘤。這五朵花分為...
    萌子莫閱讀 1,009評論 0 3
  • 最近看到太多人都在抱怨翠肘,抱怨的內(nèi)容各種各樣,我自己也是這樣辫秧,最近過的很糟糕束倍,不被理解,不被接受盟戏,找不到一個(gè)合適的詞...
    你還記得么閱讀 216評論 8 2