近平常常python的編碼問題糾纏的生活不能自理. 昨天終於靜下心來看了看文檔, 把Python3中的編碼搞清, 用這篇文章分享記錄一下(包括utf-8的原理).
python
下文中都是以python3爲栗子🌰.
由於python3慢慢變成主流, 並且用python2的話我通常會寫成兼容的模式:
>>> from __future__ import print_function, unicode_literals
算法
編碼在python2和3中的區別(可跳過, 最後回過頭來看):
摘自Effective Python那本書:
_
In Python3:
1. bytes: sequences of 8-bit values.
2. str: sequences of Unicode characters.
bytes and str instances can’t be used with operators(like > or +)
_
In Python 2:
1. str: contains sequences of 8-bit values.
2. unicode: contains sequences of Unicode characters.
str and unicode can be used together with operators if the str only contains 7-bit ASCII characters.
_
但說實話在今天前, 我對上邊那段話的理解仍是停留在python3 有兩種類型(str和bytes)的地步😓.編碼
python3的str字符串, 默認就表明unicode字符組成的序列.spa
1
2 3 |
In [1]: s = '哈哈哈' In [2]: type(s) Out[2]: str |
那問題來了, 到底什麼是unicode呢?
你們都知道ASCII編碼, 它用7位bits表明128個字符.
但一個字節不夠用的時候, 不少聰明的人就發明了不少的擴展的字符集.
但是這時候碰到了一個問題, 就是一臺電腦在美利堅可能用的好好的, 但若是收到日本的郵件, 那就GG了, 由於兩臺電腦的編碼方式不一樣.code
全部後來更聰明的人就想到了unicode:
它對世界上全部的字符進行收集, 每一個字符指向一個code point(簡單理解爲一個惟一的數字), 這樣全世界交流也不會亂碼了, 棒棒噠.
因此unicode的一箇中文名也叫萬國碼
.blog
bytes和str同樣都是內置的類型:utf-8
1
2 3 |
In [7]: s = b'haha' In [8]: type(s) Out[8]: bytes |
我的理解, 它表明的就是以字節(byte)爲單位存儲的二進制, i.e. 一坨的bytesunicode
搞清楚python中的str和bytes類型, 這個問題就迎刃而解了.文檔
Encoding:
str → bytes
由於str只是一堆unicode字符(數字).
因此簡單的說, encoding就是把一堆數字, 按特定的編碼算法X(例如utf-8), 用字節的方式存儲在計算機上.字符串
Decoding:
bytes → str
舉個栗子🌰:
1
2 3 4 5 6 7 |
In [9]: s = '哈哈' In [10]: s.encode('utf-8') Out[10]: b'\xe5\x93\x88\xe5\x93\x88' In [11]: s.encode().decode('utf-8') Out[11]: '哈哈' |
簡單的說下unicode是如何經過utf-8編碼轉化爲bytes, 以幫助更好的理解什麼是編碼(encoding).
utf-8其實屬於 動態長度編碼(variable length encoding).
舉個動態長度編碼簡單的栗子, 假如說有這麼一個二進制序列:
10010001, 10000001, 10110010, 10110010
咱們就能夠利用每一個byte的最後一位(標誌位, 1表明繼續, 0表明結束), 來判斷讀幾個bytes.
utf-8也是相似的思想, 但不一樣於上邊, 它是用每一個字節開頭的幾位, 看成標誌位, 以下表所示:
1st Byte | 2nd Byte | 3rd Byte | 4th Byte | 可用的Bits | 最大值 |
---|---|---|---|---|---|
0xxxxxxx | 7 | 007F hex (127) | |||
110xxxxx | 10xxxxxx | (5+6)=11 | 07FF hex (2047) | ||
1110xxxx | 10xxxxxx | 10xxxxxx | (4+6+6)=16 | FFFF hex (65535) | |
11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx | (3+6+6+6)=21 | 10FFFF hex (1,114,111) |
(生動活潑形象的編碼例子見下圖↓)
爲此我專門畫了一張圖, 總結了一下:
1
2 3 4 5 6 7 8 9 |
'unicode: 01010110 00111111' +--- _str = '嘿' <---+ | | encoding | | decoding | | +---> _bytes = b'\xe5\x98\xbf' ----+ 'utf-8: (1110)0101 (10)011000 (10)11 1111' |
!注意utf-8編碼中我用括號括起來的部分, 去對照上邊的表格(第三排).