字符與編碼:ASCII碼、Unicode和UTF-8


字符與編碼的問題,之前很少深究,但這次遇到了base64的問題,所以覺得是時候解決一下了,不一定全面,但想盡可能記錄一些想知道的點。。。

  • 首先,為什么需要編碼??因為計算機本身可不認識:‘你在做什么?’、‘what are you doing?’等這么人類性的語言;在計算機內部,所有的信息都表示為一個二進制的字符串。而每一個二進制位(bit)有0和1兩種狀態,具體哪些二進制數表示什么字符,多少位表示什么字符,需要有一個標准,也就是編碼。
  • 字節(Byte):是計量存儲容量的單位,是構成信息的一個很小的單位,上面還有KB、MB、GB、TB、PB、EB、ZB、YB等;下面還有bit(位)。
  • 字符:各種文字、符號的總稱。例如文字、標點、圖形、數字、字母等等。
  • 字符集:顧名思義,就是一定數量的字符組成的集合,字符集種類比較多,而且每個字符集包含的字符個數也不同,常見字符集主要有:ASCII字符集、GB2312字符集、BIG5字符集、 GB18030字符集、Unicode字符集等,字符集為每一個【字符】分配一個唯一的 ID(學名為碼位 / 碼點 / Code Point)。
  • 字符編碼:將字符集中的每個字符映射為字節流的實現方案(編碼方案),即屬於將【碼位】轉換為字節序列的規則,便於計算機存儲和傳輸;常見的字符編碼有ASCII編碼、UTF-8編碼、GBK編碼、Base64編碼等。某種意義上來說,字符集與字符編碼有種對應關系,例如 ASCII字符集對應有ASCII編碼。
  • 編碼與解碼:編碼的過程是將字符轉換成字節流,解碼的過程是將字節流解析為字符。

1. ASCII碼:(American Standard Code for Information Interchange) 美國信息交換標准碼,是美國制定的單字節字符編碼系統,作用於ASCII字符集,見附錄1

因為在英語中,128個符號就可以滿足,所以一直將1個字節(8位)的最高位閑置(默認為0),其他7位用於編碼;后來才擴展了最高位,共可以表示256個符號

例如:字符A,ASCII碼是65(十進制),二進制是01000001,八進制是0101,十六進制是0x41。

但是,即使256位,也是不夠用的,因為世界上的國家和文字、符號太多了,於是就開始擴展,出現了Unicode字符集。

2. Unicode字符集

注意:Unicode是一個符號集,包含了各國的符號、文字等,詳細可查;它只規定了字符對應的二進制代碼,卻沒有規定這個二進制代碼應該如何存儲。

於是出現了Unicode字符集對應的編碼方式,主要是utf-8,也有utf-16、utf-32等,但utf-8是在互聯網上使用最廣的一種Unicode的實現方式。utf-8最大的一個特點,就是它是一種變長的編碼方式。它可以使用1~4個字節表示一個符號,並且根據不同的符號需要而變化字節長度。

3. utf-8編碼

utf-8的編碼規則是:

1)對於單字節的符號,字節的第一位設為0,后面7位為這個符號的unicode碼。所以對於英文字符,utf-8編碼和ASCII碼相同。

2)對於n字節的符號(n>1),第一個字節的前n位都為1,第n+1位為0,(其第一個字節從最高位開始,連續的二進制位為1的個數決定了其編碼的字節數n),后面各字節的前兩位一律為10。剩下的沒有提及的二進制位,全部為這個符號的unicode碼。

其編碼規則如下:

# ---------------------------------------------------------------

Unicode符號范圍(十六進制) |  UTF-8編碼方式(二進制)

0000 0000-0000 007F   |    0xxxxxxx
0000 0080-0000 07FF   |   110xxxxx 10xxxxxx
0000 0800-0000 FFFF   |   1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF   |   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

# ---------------------------------------------------------------

4. 示例,獲取漢字 '龍' 的utf-8編碼值

第一步,獲取 '龍' 的Unicode值:ord('龍') —— python內置函數ord,得到:40857

第二步,求得Unicode值的十六進制:hex(40857) —— 得到:9f00

第三步,獲取utf-8編碼:其實python有函數進行編碼 —— '龍'.encode('utf-8'),可得:b'\xe9\xbe\x99',也即是:e9be99

其求取方法如下:

(1)求取 Unicode值對應的二進制值:十進制轉二進制 —— python內置函數,bin(40857),得到:'0b1001111110011001',即:'1001111110011001'。

(2)由其十六進制:9f00,對應utf-8的編碼規則,0800<9f00<ffff,所以屬於三字節類型,上述規則第三行,即屬於:'1110xxxx 10xxxxxx 10xxxxxx' 類型。

(3)從得到的二進制中,最后一個二進制位開始,依次從后向前代入上述格式中的 'x' 中,多出的位補0。

(4)於是得到:11101001  10111110  10011001,對應的十六進制為:e9  be  99,因為每4位二進制組成一個十六進制。

# ----------------------------------------------------------------

5. 獲取 utf-8 編碼的字節長度 —— 先編碼,再len()

b = ''.encode('utf-8')   # utf-8 編碼
print('b:',b)  #  結果中開頭的 b 字符表示bytes類型,'\x'表示十六進制數據
print(type(b)) # 類型是'bytes'

print(len(b))  # 編碼的字節數,3個字節編碼,因為b就是字節類型 bytes

6. utf-8 解碼和編碼

t = ''
str_ = t.encode('utf-8')   # 編碼得到字節流
print(str_)
uni_ = str_.decode('utf-8')  # 通過字節流,進行解碼獲取字符串
print(uni_)

7. 英文字母在計算機內存儲的是機內碼,也就是ASCII碼,因為英文字母的機內碼就是ASCII碼。而每一個漢字在不同的編碼下也有對應的內碼。

utf-8 用3個字節來表示常用的一個中文字符,1個字節來表示英文字符,兼容ASCII碼;

gbk、gb2312 用2個字節來表示一個中文字符,1個字節來表示英文字符,兼容ASCII碼,gbk向下兼容gb2312,gb18030向下兼容gbk和gb2312;

b = 'm'.encode('gbk') 
print('b:',b)  #  開頭的 b 字符表示bytes類型
print(type(b))   #類型是'bytes'

print(len(b))  #編碼的字節數,因為上面先進行了編碼

8. sys.getsizeof() 返回對象的內存大小:不僅僅包括字符等數據的字節數,還包含很多附帶的內存開銷,例如垃圾收集器等;就像一個word文檔,即使什么都沒寫,也會有9kB的大小,因為它包含了word的頭部信息。

 

附錄1:ASCII碼表

參考:

https://www.cnblogs.com/wangxiaorui/p/5287975.html

https://baike.baidu.com/item/ASCII/309296?fromtitle=ascii%E7%A0%81&fromid=99077&fr=aladdin

https://tool.oschina.net/commons?type=4

https://zhuanlan.zhihu.com/p/25148581

https://www.zhihu.com/question/23374078

http://www.cocoachina.com/articles/53800


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM