Python 3中的默認編碼
Python3中默認是UTF-8
可查看Python3的默認編碼。
>>> import sys >>> >>> sys.getdefaultencoding() 'utf-8' >>>
系統默認編碼 指:
在python 3編譯器讀取.py文件時,若沒有頭文件編碼聲明,則默認使用“utf-8”來對.py文件進行解碼。並且在調用 encode()這個函數時,不傳參的話默認是“ utf-8 ”。(這與下面的open( )函數中的“encoding”參數要做區分)
本地默認編碼 指:
在你編寫的python 3程序時,若使用了 open( )函數 ,而不給它傳入 “ encoding ” 這個參數,那么會自動使用本地 Windows 或 Linux 的默認編碼。沒錯,如果在Windows系統中,就是默認用gbk格式!所以請大家在這里注意:linux中可以不用傳“ encoding” 的參數, 而win中不能忘了“ encoding” 的參數)
utf-8是可變長的的編碼,有1個字節的英文字符,也有2個字節的阿拉伯文,也有3個字節的中文和日文。utf-8是有嚴格定義的,一個字節的字符高位必須是0;三個字節的字符中,第一個字節的高位是1110開頭。
gbk對英文是使用單字節編碼(也就意味着兼容ascii),而gbk對中文部分是采取定長的2字節,總體編碼范圍為 8140-FEFE,首字節在 81-FE 之間,尾字節在 40-FE 之間。所以說它只要沒有碰到尾字節在40之內的字符,都會一股腦地按照2字節去解碼成中文。而中文在 utf-8 編碼后,一般是三字節的。當解碼的字節數和編碼的字節數不匹配時,自然會造成全是亂碼的局面。
實際上unicode就是一個字符集,一個字符與數字一一對應的映射關系,因為它一律以2個字節編碼(或者也有4個字節的,這里不討論),所以占用空間會大一些,一般只用於內存中的編碼使用。
而 utf-8 是為了實現unicode 的傳輸和存儲的。因為它可變長,存英文時候可以節省大量存儲空間。傳輸時候也節省流量。
進程在內存中的表現是“ unicode ”的編碼;當python3編譯器讀取磁盤上的.py文件時,是默認使用“utf-8”的;當進程中出現open(), write() 這樣的存儲代碼時,需要與磁盤進行存儲交互時,則是默認使用操作系統的默認編碼。
Python 3中的encode和decode
Python3中字符編碼經常會使用到decode和encode函數。特別是在抓取網頁中,這兩個函數用的熟練非常有好處。encode的作用,使我們看到的直觀的字符轉換成計算機內的字節形式。decode剛好相反,把字節形式的字符轉換成直觀的形式。
>>> "西安".encode() b'\xe8\xa5\xbf\xe5\xae\x89' >>> b'\xe8\xa5\xbf\xe5\xae\x89'.decode() '西安'
\x表示后面是十六進制
在Python 3中, 以字節形式表示的字符串則必須加上前綴b,也就是寫成上文的b'xxxx'形式。
UTF-8兼容ASCII
Python3中的編碼轉換
字符以Unicode的字節形式表現出來
>>> "西安".encode('unicode-escape') b'\\u897f\\u5b89' >>> b'\\u897f\\u5b89'.decode('unicode-escape') '西安'
如果我們知道一個Unicode字節碼,怎么變成UTF-8的字節碼,先decode,再encode。
>>> "西安".encode('unicode-escape') b'\\u897f\\u5b89' >>> "西安".encode('unicode-escape').decode('unicode-escape') '西安' >>> "西安".encode('unicode-escape').decode('unicode-escape').encode() b'\xe8\xa5\xbf\xe5\xae\x89'
源代碼文件中,如果有用到非ASCII字符,則需要在文件頭部進行字符編碼的聲明,如下:
#-*- coding: UTF-8 -*-
python3中的字符序列也有兩種類型:bytes和str。python3中的bytes和python2中的str相似,str和python2中的unicode相似。這里要注意,str類型在python3和python2中都有,但含義完全變了。
unicode_string=u'中國' print(len(unicode_string)) print( type(unicode_string)) str_string = unicode_string.encode('utf-8') print(len(str_string)) str_string print(type(str_string)) >>> unicode_string=u'中國' >>> print(len(unicode_string)) 2 >>> print( type(unicode_string)) <class 'str'> >>> str_string = unicode_string.encode('utf-8') >>> print(len(str_string)) 6 >>> str_string b'\xe4\xb8\xad\xe5\x9b\xbd' >>> print(type(str_string)) <class 'bytes'>
UnicodeEncoderError
將文本轉化為字節序列時,若有字符在目標編碼中沒有定義,則會出現UnicodeEncoderError。
由於中文字符在ascii編碼中無定義,則會報出編碼錯誤。對於此類問題,需選擇合適的編碼類型,比如含有中文字符,一般用UTF-8編碼類型對unicode字符串編碼。
>>> unicode_string=u'平國' >>> unicode_string.encode('ascii') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
UnicodeDecodeError
把二進制序列轉化為文本時,遇到無法轉換的字節序列,則會發生此異常。比如用UTF-8編碼后的二進制序列,用GB2312解碼,由於兩種編碼不兼容,用GB2312不能識別字節序列,則會出現異常。
unicode_string=u'中國' utf8_string=unicode_string.encode('utf-8') utf8_string.decode('GB2312')
碰到這種異常,是由於decode使用的編碼和字節序列的編碼不一致,可以用字符編碼偵測包chardet檢測字節序列的編碼,然后再用此編碼解碼。
import chardet ### pip install chardet utf8_string=u"中國" str_type=chardet.detect(utf8_string) str_type
#python 3,str和bytes類型相互轉換工具類 #file:python3_endecode_helper.py def to_str(bytes_or_str): if isinstance(bytes_or_str,bytes): value = bytes_or_str.decode('UTF-8') else: value = bytes_or_str return value def to_bytes(bytes_or_str): if isinstance(bytes_or_str,str): value = bytes_or_str.encode('UTF-8') else: value = bytes_or_str return value if __name__=='__main__': str_string = u'中國' value = to_bytes(str_string) print(type(value)) #<class 'bytes'> value = to_str(value) print(type(value)) #<class 'str'>
# coding:gbk import sys import locale def p(f): print('%s.%s(): %s' % (f.__module__, f.__name__, f())) # 返回當前系統所使用的默認字符編碼 p(sys.getdefaultencoding) # 返回用於轉換Unicode文件名至系統文件名所使用的編碼 p(sys.getfilesystemencoding) # 獲取默認的區域設置並返回元組(語言, 編碼) p(locale.getdefaultlocale) # 返回用戶設定的文本數據編碼 # 文檔提到this function only returns a guess p(locale.getpreferredencoding) # 在筆者的Windows上的結果 # sys.getdefaultencoding(): utf-8 # sys.getfilesystemencoding(): utf-8 # locale.getdefaultlocale(): ('en_US', 'cp936') # locale.getpreferredencoding(): cp936
REF
https://www.cnblogs.com/killianxu/p/9746545.html
https://www.cnblogs.com/huxi/archive/2010/12/05/1897271.html
https://blog.csdn.net/ym01213/article/details/89083428
https://zhuanlan.zhihu.com/p/40834093