解決程序中的字符編碼問(wèn)題

今天臺(tái)風(fēng)過(guò)境,風(fēng)雨交加,突然就想寫一下這個(gè)在學(xué)習(xí)編程初期,非常困擾的問(wèn)題。
我會(huì)盡我所能將這個(gè)問(wèn)題描述清楚,如果有不當(dāng)之處還請(qǐng)指正!
轉(zhuǎn)載請(qǐng)注明出處即可



字符與字節(jié)

字符 就是我們平??吹靡?jiàn)的這些,比如 '1','c',"中文", 在程序代碼中它們往往表現(xiàn)為一個(gè)字符串(其實(shí)字符的范圍要廣得多,還包括不可見(jiàn)的控制字符,后來(lái)出現(xiàn)的 emoj 字符等)

但是我們知道其實(shí)計(jì)算機(jī)內(nèi)部都是只含 01 的二進(jìn)制序列,于是又引出了兩個(gè)概念
字節(jié) ,比如 \x31, \xff,它們才是實(shí)際在計(jì)算機(jī)中存儲(chǔ)的東西

而從字符到字節(jié)的映射,就是 字符編碼

ASCII 編碼

這是我們經(jīng)常聽(tīng)到的編碼,在 ASCII 編碼中,可見(jiàn)字符 '1','2','a','f' 或者 控制字符 '\n','\b' 等都被編碼為一個(gè)字節(jié)

其他編碼

其他編碼多種多樣,比如 GBK,GB2312 等,它們可以表示漢字,將每個(gè)漢字編碼為多個(gè)字節(jié)
所以也就出現(xiàn)了所謂 多字節(jié)字符 的概念

使用范圍最廣的應(yīng)該是 UTF-8 編碼,它用 1-6 的字節(jié)來(lái)編碼世界上所有的字符,包括拉丁字符,中文字符,西洋字符,emoj 字符等等,幾乎所有

編碼報(bào)錯(cuò)

了解了這些就能理解為什么 編碼出錯(cuò),解碼出錯(cuò) 等概念了,亂碼 也是一樣的道理
哪些地方會(huì)出現(xiàn)編碼問(wèn)題呢?我們分幾個(gè)場(chǎng)景來(lái)闡述

  1. 記事本(文本編輯器)

當(dāng)我們將一堆字符敲完了,保存時(shí)文本編輯器一般都會(huì)有提示,你想以什么格式保存?

舉個(gè)栗子會(huì)比較直觀: 我們敲入了 '中文',保存時(shí)選擇 UTF-8 編碼,那么計(jì)算機(jī)內(nèi)部就存儲(chǔ)一個(gè) '\xe4\xb8\xad\xe6\x96\x87',如果選擇 GBK 編碼,那么就存儲(chǔ)一個(gè) '\xd6\xd0\xce\xc4',這是編碼的過(guò)程

相應(yīng)的我們關(guān)閉編輯器后重新打開,可以選擇以什么編碼格式來(lái)打開,這就是解碼的過(guò)程
所以如果編碼方式和解碼方式不一致,自然就無(wú)法將字節(jié)('\xe4\xb8\xad\xe6\x96\x87')轉(zhuǎn)為 我們期望的字符('中文'

了解清楚了么,然后我們開始擴(kuò)展到更多情景
ps: 不要用記事本寫代碼,容易編碼出錯(cuò)是一方面,主要顯得太 low 了

  1. 我們將字符串賦值給一個(gè)變量,然后輸出到屏幕

這里除了要保證源代碼文件保存時(shí)的編碼和重新打開時(shí)的編碼一致之外,多了一點(diǎn)需要注意

當(dāng)程序運(yùn)行起來(lái)的時(shí)候,程序內(nèi)部也有自己的編碼方式(wtf?),這里以 python2 為例

python2 內(nèi)部默認(rèn)格式是 unicode ,然而它也允許另外一種格式 str,em...

>>> s = '中文'
>>> s
'\xe4\xb8\xad\xe6\x96\x87'
>>> type(s)
<type 'str'>

可以看到這就是我們的字符串它的類型是 str,編碼方式是 UTF-8
所以我們用 UTF-8 來(lái)解碼一下,嗯,得到了一個(gè) unicode 類型,真不錯(cuò)

>>> s.decode('utf-8')
u'\u4e2d\u6587'
>>> type(s.decode('utf-8'))
<type 'unicode'>

python 一定也是這么做的吧
no... 在 python2 中,默認(rèn)使用 ascii 格式來(lái)處理的
也就是說(shuō),當(dāng) python2 檢測(cè)到該字符串不是 unicode 類型,就嘗試用 ascii 去解碼,即 s.decode('ascii')
相應(yīng)的,在輸出的時(shí)候,檢測(cè)到該字符串不是 str 類型,就嘗試用 ascii 去編碼

所以你就遇到了這樣兩個(gè)錯(cuò)誤
UnicodeEncodeError: 'ascii' codec can't encode characters
UnicodeDecodeError: 'ascii' codec can't decode characters

對(duì)于這個(gè)編碼轉(zhuǎn)換發(fā)生在什么時(shí)候我不太清楚,知道的請(qǐng)告訴我!
不過(guò)這樣下去總不是個(gè)事兒
最好的解決方法就是遷移到 python3 吧(強(qiáng)烈推薦)

python3 統(tǒng)一了字符串表示用 str,內(nèi)部存儲(chǔ)用的是 bytes,默認(rèn)編碼格式是 UTF-8!
更多信息自己去查詢,這里有點(diǎn)跑偏了

  1. 我們?yōu)g覽網(wǎng)頁(yè)的時(shí)候

與上述情況類似,數(shù)據(jù)在網(wǎng)絡(luò)上傳播的形式是 比特流/字節(jié)流,這就意味著還是要編碼

存儲(chǔ)在服務(wù)器的網(wǎng)頁(yè)信息(字符),在服務(wù)端編碼變成比特流/字節(jié)流,然后我們的瀏覽器拿到這些比特流/字節(jié)流,解碼成(我們實(shí)際看到的)網(wǎng)頁(yè)(字符)

編碼解碼不一致就又會(huì)亂碼啦!
不過(guò)一般網(wǎng)頁(yè)都會(huì)指定編碼方式 <meta charset="utf-8"/>
瀏覽器也會(huì)按指定格式解碼,一般沒(méi)事
出錯(cuò)了調(diào)整下瀏覽器編碼方式試試

結(jié)語(yǔ)

差不多就這么多了,點(diǎn)個(gè)關(guān)注嘛..

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容