字符編碼及其在 C++ 與 Python 中的使用

作者:CPPFive

在網(wǎng)上爬句子的時(shí)候碰到了編碼轉(zhuǎn)換的問題飒焦。因?yàn)楹芏嗝嫦蚴澜绶秶W(wǎng)頁上普遍使用 UTF-8 編碼那槽,而本地默認(rèn)使用的是 GBK(準(zhǔn)確來說是CP936悼沿,很類似 GBK 但不完全一樣)編碼,并且將 UTF-8 編碼直接轉(zhuǎn)換成 GBK 編碼有概率會爆出亂碼(UTF-8 編碼對應(yīng)的字符集大于 GBK)骚灸,所以我們需要一種能在本地處理 UTF-8 的方法糟趾。這里主要介紹一些關(guān)于計(jì)算機(jī)編碼的基本知識以及在 C++ 和 Python 中處理不同編碼的文件的方式。

編碼

字符是以二進(jìn)制形式存儲在電腦中的甚牲。而為了使電腦中存儲的二進(jìn)制編碼可以在不同的電腦上被使用义郑,就需要通用的編碼方式,即有一套類似于密碼表一樣的東西丈钙,使得每一個(gè)字符都可以與一個(gè)二進(jìn)制數(shù)(這個(gè)二進(jìn)制數(shù)通常被稱為碼位)相對應(yīng)非驮。ASCII 碼就是非常基礎(chǔ)的一套“密碼表”雏赦,可以將常見符號以及英文字母對應(yīng)成二進(jìn)制數(shù)劫笙。但是ASCII碼的每個(gè)字符只使用八個(gè)二進(jìn)制位來存儲,所以最多也只能對應(yīng) 256 個(gè)字符(實(shí)際上標(biāo)準(zhǔn) ASCII 碼只使用七個(gè)二進(jìn)制位星岗,只包含 128 個(gè)字符)填大。而為了存儲更多語言的字符,出現(xiàn)了更大的字符集俏橘。

Unicode

統(tǒng)一碼(Unicode)允华,也叫萬國碼、單一碼寥掐,是計(jì)算機(jī)科學(xué)領(lǐng)域里的一項(xiàng)業(yè)界標(biāo)準(zhǔn)例获,包括字符集、編碼方案等曹仗。Unicode 是為了解決傳統(tǒng)的字符編碼方案的局限而產(chǎn)生的榨汤,它為每種語言中的每個(gè)字符設(shè)定了統(tǒng)一并且唯一的二進(jìn)制編碼,以滿足跨語言怎茫、跨平臺進(jìn)行文本轉(zhuǎn)換收壕、處理的要求。

以上是度娘上的定義轨蛤。Unicode 指的并不是某一個(gè)字符集或者編碼方式蜜宪,而是一項(xiàng)包含了若干字符集以及編碼方式的編碼標(biāo)準(zhǔn)。我們知道 ASCII 碼的每一個(gè)字符用一個(gè)八位二進(jìn)制數(shù)存儲祥山,而 Unicode 為了容納更多字符圃验,使用了更多字節(jié)。Unicode 中常用的字符集有 UCS-2(Universal Character Set coded in 2 octets)以及 UCS-4 缝呕,前者使用兩個(gè)字節(jié)澳窑,后者使用四個(gè)字節(jié)斧散,這些字符集中每一個(gè)字符對應(yīng)的二進(jìn)制數(shù)被稱為它的碼位(code point)。UCS-2 共可以容納 65536 個(gè)字符摊聋,而后來為了容納更多文字鸡捐,才發(fā)展出了 UCS-4,后者共可以容納 1114112 個(gè)字符麻裁,人類文明所創(chuàng)造出的字符總量目前還遠(yuǎn)未達(dá)到這個(gè)數(shù)字箍镜。

要注意的是,UCS-2 和 UCS-4 僅僅規(guī)定了文字和它的碼位之間的對應(yīng)關(guān)系煎源,并沒有規(guī)定這些碼位在計(jì)算機(jī)中如何存儲色迂。事實(shí)上,由于常用字符并不需要這么大的空間來存儲手销,因此可以通過一些編碼方式來節(jié)省空間脚草,即通過某種方式將較長的碼位一一對應(yīng)為較短的實(shí)際編碼。這些編碼方式被稱為 UTF(Unicode Transformation Format)原献,其中應(yīng)用較多的是 UTF-16 和 UTF-8馏慨。通常字符通過這些編碼方式存儲在計(jì)算機(jī)中。

GB2312姑隅、GBK写隶、GB18030

三者都是國內(nèi)常用的編碼標(biāo)準(zhǔn),其中 GB2312 和 GB18030 屬于國家標(biāo)準(zhǔn)讲仰,GBK 則是二者中承上啟下的部分慕趴。由于某些歷史原因,GBK 至今仍然在國內(nèi)被大量使用鄙陡。

與 Unicode 字符相比冕房,這幾種編碼標(biāo)準(zhǔn)有如下的幾點(diǎn)不同:

  1. 編碼不同(廢話),比如“國”這個(gè)字趁矾,在 UTF-8 中編碼為 E59BBD(編碼通常用十六進(jìn)制數(shù)表示)耙册,在 GBK 中編碼則為 B9FA。文末附了幾個(gè)常用的查看字符編碼的方式毫捣,有興趣的讀者可以去實(shí)踐一下详拙。
  2. Unicode 中每個(gè)字符的碼位與計(jì)算機(jī)中實(shí)際存儲的信息是不同的(因?yàn)椴捎昧?UTF-8 等編碼方式),而 GB2312蔓同、GBK饶辙、GB18030 的字符集則是與它的存儲方式一致的,或者說此三者既是字符集斑粱,也是編碼方式弃揽。

GB2312 只收錄了簡體漢字和一些常用符號和字母,共收錄了 6763 個(gè)漢字;GBK 在 GB2312 的基礎(chǔ)上擴(kuò)充了一部分新增的漢字以及繁體字矿微、日語痕慢、朝鮮語中的漢字,共收錄了兩萬多個(gè)漢字和字符冷冗;GB18030 在 GBK 的基礎(chǔ)上進(jìn)一步擴(kuò)充,收錄了七萬多個(gè)漢字和字符惑艇。GB18030 字符集實(shí)際上非常大蒿辙,也與 Unicode 一樣包含了世界上大部分字符。

之所以在已經(jīng)有了 Unicode 的基礎(chǔ)上我國還要自己開發(fā) GB18030滨巴,原因是 GB18030 是完全面向我國的思灌,它的編碼方式更利于使用中文,例如在 GB18030 中存儲大部分中文字符都只需要兩個(gè)字節(jié)恭取,而 使用 UTF-8 則需要三個(gè)字節(jié)泰偿。當(dāng)然實(shí)際上由于許多主流應(yīng)用軟件與系統(tǒng)軟件都是由外國開發(fā)的,不太支持 GB18030 (尤其是 Windows)蜈垮,因此我們平常接觸更多的還是 UTF-8 或者 GBK耗跛。

不同編碼的使用

Unicode 的優(yōu)點(diǎn)是它足以容納所有語言的字符,因此可以滿足在各國之間通用的要求(想象一下假如不同國家之間使用的是各自的編碼攒发,那么每一次傳輸信息都將需要進(jìn)行編碼的轉(zhuǎn)換调塌,這是相當(dāng)繁瑣的)。但是通常使用中遠(yuǎn)遠(yuǎn)用不到那么多那么多字符惠猿,而 Unicode 中每個(gè)字符所占據(jù)的較大的空間此時(shí)就成為了負(fù)擔(dān)羔砾。所以 GBK 這一類的只包含部分語言、占用空間也較少的字符集在各國國內(nèi)仍然在大量使用偶妖。這也導(dǎo)致了我們前面提到的問題姜凄。

有些時(shí)候我們在訪問國外網(wǎng)站的時(shí)候會出現(xiàn)亂碼也是因?yàn)檫@種原因。網(wǎng)站的代碼可能使用了 UTF-8 編碼趾访,但是沒有在文檔中進(jìn)行聲明态秧,這時(shí)如果訪問者的瀏覽器默認(rèn)使用 GBK 編碼,就會出現(xiàn)亂碼扼鞋。

C++中的編碼問題

C++中提供了寬字節(jié) wchar_t 以及相應(yīng)的一些函數(shù)(其實(shí)就是原來的函數(shù)前面加個(gè) w)來處理 Unicode 字符屿聋。似乎由于UTF-16 的大部分常用字符都是兩個(gè)字節(jié),而一個(gè)寬字節(jié)恰好也是兩個(gè)字節(jié)藏鹊,所以可以直接處理润讥。代碼如下所示:

wstring sss;
wifstream go("test.txt");
go >> sss;
wofstream back("100.txt");
back << sss;

但以上代碼無法處理使用 UTF-8 編碼的文件,好在 C++ 提供了相應(yīng)的函數(shù)盘寡。我們可以使用 locale 函數(shù)來調(diào)整輸入/輸出流采用的編碼方式楚殿,這樣就可以處理 UTF-8 編碼的文件了。代碼如下:

wstring sss;
locale china(".65001");
wifstream go("test.txt");
go.imbue(china);
go >> sss;
wofstream back("100.txt");
back.imbue(china);
back << sss;

上面的 china 是locale 類中的一個(gè)實(shí)例,括號里的 .65001 是系統(tǒng)中 UTF-8 的編號脆粥。系統(tǒng)中編碼方式被稱為”活動代碼頁“砌溺,不同的活動代碼頁有不同的編號,文末附了一份常用編碼方式對應(yīng)代碼頁編號的列表变隔。

另外规伐,需要注意的是,如果是要輸出到命令行里的話匣缘,那么輸出流是會受限于命令行的編碼方式的猖闪。如果一定要輸出到命令行中,可以參考這篇文章來修改命令行使用的編碼方式肌厨。

非常有意思的是培慌,如果用 CP936(即 GBK)來輸入輸出 UTF-8 的文件,那么在有些時(shí)候不會出現(xiàn)亂碼柑爸,另一些時(shí)候則會出現(xiàn)吵护。

源文件

目標(biāo)文件中可以正常顯示

源文件

目標(biāo)文件出現(xiàn)亂碼

經(jīng)過不完全測試,在輸出大部分漢字以及純 ASCII 字符的時(shí)候都不會出現(xiàn)問題表鳍,但是當(dāng)文件中包含字符”四“時(shí)就會出現(xiàn)亂碼(應(yīng)該是一部分漢字會導(dǎo)致問題)馅而,并且在 ASCII 字符和中文混合使用的時(shí)候也必定會出現(xiàn)亂碼。

Python中的字符編碼問題

Python 非常的強(qiáng)大譬圣,這一點(diǎn)是毫無疑問的用爪。在字符編碼的問題上,Python 明顯比 C++ 方便得多胁镐。Python3 中的字符串(即str)統(tǒng)一以 Unicode 字符的形式保存偎血。(Unicode 并不是一種編碼方式。之所以說 Python3 使用 Unicode 字符保存字符串盯漂,是因?yàn)樵诰W(wǎng)上查不到其具體的編碼方式颇玷,只有這種籠統(tǒng)的介紹;經(jīng)過本人測試就缆,Python3 中一個(gè)英文字符占一個(gè)字節(jié)帖渠,一個(gè)常用中文字符占兩個(gè)字節(jié),所以應(yīng)該可以排除單獨(dú)使用的 UTF-8竭宰、UTF-16 或者 UTF-32 的可能空郊;比較有可能是多種編碼方式混合使用)。而在讀入和輸出時(shí)切揭,Python3 會自動根據(jù)文件的類型來完成轉(zhuǎn)換狞甚。以下面的代碼為例:

with open("test.txt","r",encoding='utf-16') as f,open("100.txt","w",encoding='utf-8') as p:
    sss=f.readline()
    p.write(sss)
    f.close()
    p.close()

上面的程序從一個(gè) UTF-16 編碼的文件讀取內(nèi)容,存儲到一個(gè)字符串中廓旬,再以 UTF-8 編碼輸出到文件中哼审。只需要指定文件的編碼方式,Python3 就會為你做好一切。如果不指定的話涩盾,Python3 會默認(rèn)使用系統(tǒng)的編碼方式十气。

正文就到這里結(jié)束啦,歡迎大家點(diǎn)贊評論支持一下(~ ̄▽ ̄)~

查看字符編碼的方式

1.在線轉(zhuǎn)換

點(diǎn)這里

2.使用 Python 查看

dest = "中"      # 待查看編碼的字符/字符串 
dest_encode = dest.encode("utf-8")      # utf-8 可以換成別的編碼方式
print(dest_encode)

3.使用 Word

在 Word 里可以通過 alt+X 來將光標(biāo)前的漢字/UTF-16 編碼互相轉(zhuǎn)換春霍。暫時(shí)不太清楚是否可以轉(zhuǎn)換成別的編碼砸西。

常用編碼方式對應(yīng)代碼頁編號的列表

代碼頁       國家(地區(qū))或語言 
437          美國 
708          阿拉伯文(ASMO 708)
720          阿拉伯文(DOS)
850          多語言(拉丁文 I) 
852          中歐(DOS) - 斯拉夫語(拉丁文 II) 
855          西里爾文(俄語) 
857          土耳其語 
860          葡萄牙語 
861          冰島語 
862          希伯來文(DOS)
863          加拿大 - 法語 
865          日耳曼語 
866          俄語 - 西里爾文(DOS) 
869          現(xiàn)代希臘語
874          泰文(Windows)
932          日文(Shift-JIS)
936          中國 - 簡體中文(GB2312)
949          韓文
950          繁體中文(Big5)
1200         Unicode        
1201         Unicode (Big-Endian)
1250         中歐(Windows)
1251         西里爾文(Windows)
1252         西歐(Windows)
1253         希臘文(Windows)
1254         土耳其文(Windows)
1255         希伯來文(Windows)
1256         阿拉伯文(Windows)
1257         波羅的海文(Windows)
1258         越南文(Windows)
20866        西里爾文(KOI8-R)
21866        西里爾文(KOI8-U)
28592        中歐(ISO)
28593        拉丁文 3 (ISO)
28594        波羅的海文(ISO)
28595        西里爾文(ISO)
28596        阿拉伯文(ISO)
28597        希臘文(ISO)
28598        希伯來文(ISO-Visual)
38598        希伯來文(ISO-Logical)
50000        用戶定義的
50001        自動選擇
50220        日文(JIS)
50221        日文(JIS-允許一個(gè)字節(jié)的片假名)
50222        日文(JIS-允許一個(gè)字節(jié)的片假名 - SO/SI)
50225        韓文(ISO)
50932        日文(自動選擇)
50949        韓文(自動選擇)
51932        日文(EUC)
51949        韓文(EUC)
52936        簡體中文(HZ)
65000        Unicode (UTF-7)
65001        Unicode (UTF-8)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市址儒,隨后出現(xiàn)的幾起案子芹枷,更是在濱河造成了極大的恐慌,老刑警劉巖离福,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件杖狼,死亡現(xiàn)場離奇詭異炼蛤,居然都是意外死亡妖爷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進(jìn)店門理朋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來絮识,“玉大人,你說我怎么就攤上這事嗽上〈紊啵” “怎么了?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵兽愤,是天一觀的道長彼念。 經(jīng)常有香客問我,道長浅萧,這世上最難降的妖魔是什么逐沙? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮洼畅,結(jié)果婚禮上吩案,老公的妹妹穿的比我還像新娘。我一直安慰自己帝簇,他們只是感情好徘郭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著丧肴,像睡著了一般残揉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上芋浮,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天冲甘,我揣著相機(jī)與錄音,去河邊找鬼。 笑死江醇,一個(gè)胖子當(dāng)著我的面吹牛濒憋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播陶夜,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼凛驮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了条辟?” 一聲冷哼從身側(cè)響起黔夭,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎羽嫡,沒想到半個(gè)月后本姥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡杭棵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年婚惫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片魂爪。...
    茶點(diǎn)故事閱讀 39,739評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡先舷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出滓侍,到底是詐尸還是另有隱情蒋川,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布撩笆,位于F島的核電站捺球,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏夕冲。R本人自食惡果不足惜氮兵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望耘擂。 院中可真熱鬧胆剧,春花似錦、人聲如沸醉冤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蚁阳。三九已至铃绒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間螺捐,已是汗流浹背颠悬。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工矮燎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人赔癌。 一個(gè)月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓诞外,卻偏偏與公主長得像,于是被迫代替她去往敵國和親灾票。 傳聞我的和親對象是個(gè)殘疾皇子峡谊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評論 2 354