python--字符/文本编码解码笔记
字符/文本編碼解碼筆記
- 1.字符問題
- 編碼和解碼
- 2.字節(jié)概要
- 3.基本的編解碼器
- 編碼類型史
- 字符編碼
- ASCII碼
- GB2312以及其他編碼
- UNICODE標(biāo)準(zhǔn)編碼
- UTF-8編碼
- 4.了解編解碼問題
- 處理UnicodeEncoderError
- 解決方法:
- 處理UnicodeDecodeError
- 解決方法
- 5.修改源代碼編碼
- 6.查看文件編碼方式
- 終端查看文件編碼方式
- 代碼內(nèi)查看文件編碼方式
- 7.處理文本文件
- 查看open函數(shù)默認(rèn)編碼方式
1.字符問題
“字符串”是個(gè)相當(dāng)簡(jiǎn)單的概念:一個(gè)字符串是一個(gè)字符序列。
在 2015 年,“字符”的最佳定義是 Unicode 字符。因此,從 Python 3 的 str 對(duì)象中獲取的元素是 Unicode 字符。但是Python 3 默認(rèn)使用 UTF-8 編碼源碼。注意區(qū)分。
Unicode 標(biāo)準(zhǔn)把字符的標(biāo)識(shí)和具體的字節(jié)表述進(jìn)行了如下的明確區(qū)分。
- 字符的標(biāo)識(shí),即碼位,是 0~1 114 111 的數(shù)字(十進(jìn)制),在 Unicode 標(biāo)準(zhǔn)中以 4~6 個(gè)十六進(jìn)制數(shù)字表示,而且加前綴“U+”。例如,字母 A 的碼位是 U+0041。
- 字符的具體表述取決于所用的編碼,也就是除了Unicode以外其他編碼的表示。編碼是在碼位和字節(jié)序列之間轉(zhuǎn)換時(shí)使用的算法。比如在 UTF-8 編碼中,A(U+0041)的碼位編碼成單個(gè)字節(jié) \x41。一個(gè)字符串則編碼為由多個(gè)字節(jié)組成的字節(jié)序列。后面會(huì)多處提到字節(jié)序列,把它當(dāng)成用其他編碼器對(duì)Unicode字符編碼的結(jié)果就可以了。
編碼和解碼
編碼是把碼位轉(zhuǎn)換成字節(jié)序列的過程。通俗的講就是將Unicode編碼的字符轉(zhuǎn)化為其他編碼的字符。
解碼是把字節(jié)序列轉(zhuǎn)換成碼位的過程。通俗的講就是將其他編碼的字符轉(zhuǎn)化為Unicode編碼的字符。
輸出:
sabér 5 b'sab\xc3\xa9r' 6 sabér- 1.'sabér'字符串有5個(gè)Unicode字符。
- 2.使用UTF-8把str對(duì)象編碼成bytes對(duì)象。
- 3.bytes字面量以b開頭,表示字節(jié)序列。
- 4.字節(jié)序列 b 有 5 個(gè)字節(jié)(在 UTF-8 中,“é”的碼位編碼成兩個(gè)字節(jié))。
- 5.使用 UTF-8 把 bytes 對(duì)象(字節(jié)對(duì)象)解碼成str 對(duì)象。
由于Unicode編碼是標(biāo)準(zhǔn)編碼格式,也可以看做是沒有任何特定編碼格式的“無編碼”模式。所以,對(duì)于任何Unicode類型編碼的字符,打印時(shí)python會(huì)自動(dòng)根據(jù)環(huán)境編碼轉(zhuǎn)為特定編碼后再顯示,Python 3 為所有平臺(tái)設(shè)置的默認(rèn)編碼都是 UTF-8。
2.字節(jié)概要
Python 內(nèi)置了兩種基本的二進(jìn)制序列類型:不可變 bytes 類型和 可變 bytearray 類型。
3.基本的編解碼器
Python 自帶了超過 100 種編解碼器(codec, encoder/decoder),用于在文本和字節(jié)之間相 互轉(zhuǎn)換。每個(gè)編解碼器都有一個(gè)名稱,如 ‘utf_8’,而且經(jīng)常有幾個(gè)別名,如 ‘utf8’、‘utf-8’ 和 ‘U8’。
- 上圖有12個(gè)字符,code point表示其碼位,還有7種編碼的字節(jié)表述(十六進(jìn)制)。
- 星號(hào)表明,某些編碼(如 ASCII 和多字節(jié)的 GB2312)不能表示所有 Unicode 字符。然而,UTF 編碼的設(shè)計(jì)目的就是處理每一個(gè) Unicode 碼位。
編碼類型史
字符編碼
將人類語言轉(zhuǎn)化為計(jì)算機(jī)能夠理解的二進(jìn)制的數(shù)(0,1),我們用bit(位)來表示,通常轉(zhuǎn)化的時(shí)候是按byte(字節(jié))來處理,一個(gè)字節(jié)等于8bit。
ASCII碼
ASCII碼是人類計(jì)算機(jī)歷史上最早發(fā)明的字符集,ASCII碼是專門為表示英文、數(shù)字以及英文標(biāo)點(diǎn)符號(hào)而生。ASCII編碼使用一個(gè)字節(jié)編碼,一個(gè)字節(jié)有256種組合,足夠存儲(chǔ)這些字符。
GB2312以及其他編碼
由于中文漢字非常多,ASCII無法滿足漢字存儲(chǔ)的需求。
為了滿足國內(nèi)在計(jì)算機(jī)中使用漢字的需要,中國國家標(biāo)準(zhǔn)總局發(fā)布了一系列的漢字字符集國家標(biāo)準(zhǔn)編碼,統(tǒng)稱為GB碼,或國標(biāo)碼。
其中最有影響的是于1980年發(fā)布的《信息交換用漢字編碼字符集 基本集》,標(biāo)準(zhǔn)號(hào)為GB 2312-1980,因其使用非常普遍,也常被通稱為國標(biāo)碼。GB2312編碼通行于我國內(nèi)地;新加坡等地也采用此編碼。幾乎所有的中文系統(tǒng)和國際化的軟件都支持GB 2312。
所以,大家可以理解為,GB系列的編碼是為了適應(yīng)復(fù)雜的中文編碼而對(duì)ASCII碼的一種擴(kuò)充。
UNICODE標(biāo)準(zhǔn)編碼
每個(gè)國家都會(huì)對(duì)ASCII碼擴(kuò)展出自己的一套編碼,就存在不同編碼之間的轉(zhuǎn)換和顯示問題。為了解決這個(gè)問題,需要一套統(tǒng)一的編碼格式,即Unicode。
Unicode又被稱為統(tǒng)一碼、萬國碼;它為每種語言中的每個(gè)字符設(shè)定了統(tǒng)一并且唯一的二進(jìn)制編碼,以滿足跨語言、跨平臺(tái)進(jìn)行文本轉(zhuǎn)換、處理的要求。
Unicode編碼通常由兩個(gè)字節(jié)組成,共表示256*256個(gè)字符,即所謂的UCS-2。某些偏僻字還會(huì)用到四個(gè)字節(jié),即所謂的UCS-4。
并且Unicode兼容ASCII,在Unicode中,原本ASCII中的127個(gè)字符只需在前面補(bǔ)一個(gè)全零的字節(jié)即可。
UTF-8編碼
UNICODE編碼有個(gè)缺點(diǎn),所有語言的字符都是固定長(zhǎng)度的存儲(chǔ),有些語言的字符只需占用少量的存儲(chǔ)空間,這就導(dǎo)致浪費(fèi)了大量的存儲(chǔ)空間。
為了解決這個(gè)問題,就出現(xiàn)了一些中間格式的字符集,他們被稱為通用轉(zhuǎn)換格式,即UTF(Unicode Transformation Format)。
我們最常用的UTF-8就是這些轉(zhuǎn)換格式中的一種。UTF-8編碼其實(shí)是一種可“變長(zhǎng)”的編碼格式,即把英文變長(zhǎng)為1個(gè)字節(jié),而漢字用3個(gè)字節(jié)表示,特別生僻的還會(huì)變成4-6字節(jié)。
該部分參考:一文搞懂Python字符編碼問題
4.了解編解碼問題
雖然有個(gè)一般性的 UnicodeError 異常,但是報(bào)告錯(cuò)誤時(shí)幾乎都會(huì)指明具體的異常:UnicodeEncodeError(把字符串轉(zhuǎn)換成二進(jìn)制序列時(shí))或 UnicodeDecodeError(把二進(jìn)制序列轉(zhuǎn)換成字符串時(shí))。如果源碼的編碼與預(yù)期不符, 加載 Python 模塊時(shí)還可能拋出 SyntaxError。
處理UnicodeEncoderError
多數(shù)非 UTF 編解碼器只能處理 Unicode 字符的一小部分子集。把文本(Unicode 字符)轉(zhuǎn)換成字節(jié)序列時(shí),如果目標(biāo)編碼中沒有定義某個(gè)字符,那就會(huì)拋出 UnicodeEncodeError 異常。
解決方法:
- 1.在encode()函數(shù)中添加參數(shù)error,舉例如下:
輸出:
b'So Paulo' b'S?o Paulo' b'São Paulo'error=‘ignore’ 處理方式悄無聲息地跳過無法編碼的字符;
error='replace’把無法編碼的字符替換成 ‘?’;
error=‘xmlcharrefreplace’ 把無法編碼的字符替換成 XML實(shí)體。
以上解決是十分不妥的,損壞了數(shù)據(jù)。
編解碼器的錯(cuò)誤處理方式是可擴(kuò)展的。你可以為 errors 參數(shù)注冊(cè)額外的字符串,方法是把一個(gè)名稱和一個(gè)錯(cuò)誤處理函數(shù)傳給 codecs.register_error 函數(shù)。 參見 codecs.register_error 函數(shù)的官方文檔。
- 2.換一種編碼器,盡量使用UTF-8編碼器。
處理UnicodeDecodeError
ASCII字符有127個(gè),但是一個(gè)字節(jié)表示的空間有256個(gè)。所以不是每一個(gè)字節(jié)都包含有效的 ASCII 字符。
同理,不是每一個(gè)字符序列都是有效的 UTF-8 或 UTF-16。
把二進(jìn)制序列(字節(jié)序列)轉(zhuǎn)換成文本(Unicode字符)時(shí),如果字節(jié)序列有無效的字節(jié)時(shí),遇到無法轉(zhuǎn)換的字節(jié)序列時(shí)會(huì)拋出 UnicodeDecodeError。
舉例如下:
輸出:
Montréal Traceback (most recent call last):File "c:\Users\13451\Desktop\python基本操作\1.py", line 18, in <module>oct1=octets.decode('utf_8') UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 5: invalid continuation byte 'Montral'- 這些字節(jié)序列是使用 latin1 編碼的“Montréal”;’\xe9’ 字節(jié)對(duì)應(yīng)“é”。
- 可以使用 ‘cp1252’(Windows 1252)解碼,因?yàn)樗?latin1 的有效超集。
- ‘utf_8’ 編解碼器檢測(cè)到 octets 不是有效的 UTF-8 字符串,拋出 UnicodeDecodeError。bug中position從零開始數(shù)。
解決方法
使用 ‘replace’ 錯(cuò)誤處理方式,\xe9 替換成了替換字符(碼位是 U+FFFD),這是官方指定的 REPLACEMENT CHARACTER(替換字符),表示未知字符。替換字符:形狀為黑色菱形,且中間填充了一個(gè)問號(hào)。
5.修改源代碼編碼
Python 3 默認(rèn)使用 UTF-8 編碼源碼且Python 3 為所有平臺(tái)設(shè)置的默認(rèn)編碼都是 UTF-8。
在源代碼第一行加# coding: cp1252即可用cp1252編碼,或者編輯器或IDE都有更改編碼的途徑。
6.查看文件編碼方式
終端查看文件編碼方式
安裝統(tǒng)一字符編碼偵測(cè)包 Chardet。
終端使用:
輸出:
1.py: utf-8 with confidence 0.99表示1.py有0.99的可能是utf-8編碼。
代碼內(nèi)查看文件編碼方式
使用chardet庫的detect函數(shù)
import chardet file1='data/test.txt' f=open(file1,'rb') f_encoding=chardet.detect(f.read()) print(f_encoding) f.close()輸出:
{'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}7.處理文本文件
使用open()函數(shù)打開文件,有兩種方式處理文件:文本模式和二進(jìn)制模式。
添加encoding參數(shù)可以設(shè)置編碼方式,這個(gè)編碼方式在編碼輸出文本的時(shí)候會(huì)用到,即下圖第三行。open()函數(shù)默認(rèn)采用文本模式。默認(rèn)編碼方式取決于平臺(tái),window10下為gbk,linux下為utf-8。當(dāng)處于二進(jìn)制模式時(shí)不能添加encoding參數(shù),因?yàn)楸旧砭褪嵌M(jìn)制了,不需要再編碼。
- 如果調(diào)用read()函數(shù),open 函數(shù)會(huì)在讀取文件時(shí)做必要的解碼(自動(dòng)解碼成Unicode字符,即str)。對(duì)應(yīng)下圖解碼輸入的字節(jié)序列,得到str對(duì)象。
- 如果調(diào)用write()函數(shù),以文本模式寫入文件時(shí)還會(huì)做必要的編碼。參數(shù)為str對(duì)象。對(duì)應(yīng)下圖第三行,生成字節(jié)序列(bytes)。
整個(gè)處理文本文件的過程如下圖:
查看open函數(shù)默認(rèn)編碼方式
file1='data/test.txt' fp=open(file1,'w') print(fp) fp.close()win10下輸出:
<_io.TextIOWrapper name='data/test.txt' mode='w' encoding='cp936'>cp936即 code page 936(代碼頁936)是以GBK(國標(biāo)擴(kuò)展字符集)為基礎(chǔ)的編碼。基本和GBK差不多。
關(guān)于編碼默認(rèn)值的最佳建議是:別依賴默認(rèn)值。如果遵從 Unicode 三明治的建議,而且始終在程序中顯式指定編碼,那將避免很多問題。
參考了流暢的python第四章。
總結(jié)
以上是生活随笔為你收集整理的python--字符/文本编码解码笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑显示器白屏主机正常(显示器白屏但主机
- 下一篇: Python正则表达式笔记