1. 程式人生 > >(三)Python基礎2:瞭解字元編碼

(三)Python基礎2:瞭解字元編碼

2-str-code.py

# 瞭解字元編碼
# 字串也是一種資料型別,但是,字串比較特殊的是還有一個編碼問題。

# 因為計算機只能處理數字,如果要處理文字,就必須先把文字轉換為數字才能處理。
# 最早的計算機在設計時採用8個位元(bit)作為一個位元組(byte),所以,一個位元組能表示的最大的整數就是255(二進位制11111111=十進位制255),
# 如果要表示更大的整數,就必須用更多的位元組。比如兩個位元組可以表示的最大整數是65535,4個位元組可以表示的最大整數是4294967295。

# 由於計算機是美國人發明的,因此,最早只有127個字元被編碼到計算機裡,也就是大小寫英文字母、數字和一些符號,
# 這個編碼表被稱為ASCII編碼,比如大寫字母A的編碼是65,小寫字母z的編碼是122。

# 但是要處理中文顯然一個位元組是不夠的,至少需要兩個位元組,而且還不能和ASCII編碼衝突,所以,中國製定了GB2312編碼,用來把中文編進去。

# 你可以想得到的是,全世界有上百種語言,日本把日文編到Shift_JIS裡,韓國把韓文編到Euc-kr裡,
# 各國有各國的標準,就會不可避免地出現衝突,結果就是,在多語言混合的文字中,顯示出來會有亂碼。

# 因此,Unicode應運而生。Unicode把所有語言都統一到一套編碼裡,這樣就不會再有亂碼問題了。

# Unicode標準也在不斷髮展,但最常用的是用兩個位元組表示一個字元(如果要用到非常偏僻的字元,就需要4個位元組)。
# 現代作業系統和大多數程式語言都直接支援Unicode。

# 現在,捋一捋ASCII編碼和Unicode編碼的區別:ASCII編碼是1個位元組,而Unicode編碼通常是2個位元組。

# 字母A用ASCII編碼是十進位制的65,二進位制的01000001;

# 字元0用ASCII編碼是十進位制的48,二進位制的00110000,注意字元'0'和整數0是不同的;

# 漢字中已經超出了ASCII編碼的範圍,用Unicode編碼是十進位制的20013,二進位制的01001110 00101101。

# 你可以猜測,如果把ASCII編碼的A用Unicode編碼,只需要在前面補0就可以,因此,A的Unicode編碼是00000000 01000001。

# 新的問題又出現了:如果統一成Unicode編碼,亂碼問題從此消失了。但是,如果你寫的文字基本上全部是英文的話,
# 用Unicode編碼比ASCII編碼需要多一倍的儲存空間,在儲存和傳輸上就十分不划算。

# 所以,本著節約的精神,又出現了把Unicode編碼轉化為“可變長編碼”的UTF-8編碼。
# UTF-8編碼把一個Unicode字元根據不同的數字大小編碼成1-6個位元組,
# 常用的英文字母被編碼成1個位元組,漢字通常是3個位元組,只有很生僻的字元才會被編碼成4-6個位元組。
# 如果你要傳輸的文字包含大量英文字元,用UTF-8編碼就能節省空間:

# 三種編碼字元比較
# 字元		ASCII			Unicode					UTF-8
#  A		01000001		00000000 01000001		01000001
#  中		x				01001110 00101101		11100100 10111000 10101101


# 1. 在最新的Python 3版本中,字串是以Unicode編碼的,也就是說,Python的字串支援多語言,例如:
print('包含中文的str')

# 2. ord()函式獲取字元的整數表示
print(ord('A'))  # 65
print(ord('中')) # 20013

# 3. chr()函式把編碼轉換為對應的字元
print(chr(66))  # B
print(chr(25991)) # 文
print(chr(0x43)) # C

# 如果知道字元的整數編碼,還可以用十六進位制這麼寫str:
print('\u4e2d\u6587') # '中文'


# 4. str => bytes

# 首先區分'ABC'和 b'ABC'
# 前者是str,字串,因為本文字是Unicode編碼,所以前者'ABC'每個字元佔兩個位元組
# 後者,位元組碼,雖然內容顯示得和前者一樣,但bytes的每個字元都只佔用一個位元組
# 如果不理解,再返回最上面理解位元組和不同編碼所佔的位元組數的區別

# a. 純英文的str => bytes

# 以Unicode表示的str通過encode()方法可以編碼為指定的bytes,例如:
print(b'ABC') # b'ABC'
print('ABC'.encode('ascii')) # b'ABC'


# b. 含有中文的str => bytes

# print('中文'.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)

print('中文'.encode('utf-8')) # b'\xe4\xb8\xad\xe6\x96\x87'
# 意思是純英文的str可以用ASCII編碼為bytes,內容是一樣的,含有中文的str可以用UTF-8編碼為bytes。
# 含有中文的str無法用ASCII編碼,因為中文編碼的範圍超過了ASCII編碼的範圍,Python會報錯。

# c. 在bytes中,無法顯示為ASCII字元的位元組,用\x##顯示。能顯示的就是指ASCII碼對照表上能查到的(0-127) http://ascii.911cha.com/


# 5. bytes => str
# 要把bytes變為str,就需要用decode()方法
print(b'ABC'.decode('ascii')) # ABC

print(b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')) # 中文

###################################################################################
# 這裡有一個問題要注意: 
# 如果輸入 b'\xe4\xb8\xad\xff'.decode('utf-8'), 會報錯
# Traceback (most recent call last):
#   ...
# UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 3: invalid start byte
# 不是所有位元組碼都能正常被utf-8編碼識別 如這裡的0xff
utf8str = b'\xe4\xb8\xad\xff'.decode('utf-8', errors='ignore')
print(utf8str) # 中

print(utf8str.encode('utf-8')) # b'\xe4\xb8\xad', 不能識別的 0xff被捨棄了
# 可以先記下, 一般不會用位元組碼直接轉為utf-8編碼, 後面接觸到Base64編碼處理再說

#  編碼問題看不懂不用頭疼,以後用到時慢慢理解  ^_^			
###################################################################################