国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

PyTips 0x09 - Python 中 Unicode 的正確用法

shenhualong / 2095人閱讀

摘要:只包含了個(gè)基本拉丁字母阿拉伯?dāng)?shù)目字和英式標(biāo)點(diǎn)符號(hào)一共個(gè)字符,因此只需要不占滿一個(gè)字節(jié)就可以存儲(chǔ),而則涵蓋的數(shù)據(jù)除了視覺(jué)上的字形編碼方法標(biāo)準(zhǔn)的字符編碼外,還包含了字符特性,如大小寫字母,共可包含個(gè)字符,而到現(xiàn)在只填充了其中的個(gè)位置。

項(xiàng)目地址:https://git.io/pytips

0x07 和 0x08 分別介紹了 Python 中的字符串類型(str)和字節(jié)類型(byte),以及 Python 編碼中最常見(jiàn)也是最頑固的兩個(gè)錯(cuò)誤:

UnicodeEncodeError: "ascii" codec can"t encode characters in position 0-1: ordinal not in range(128)

UnicodeDecodeError: "utf-8" codec can"t decode bytes in position 0-1: invalid continuation byte

這一期就從這兩個(gè)錯(cuò)誤入手,分析 Python 中 Unicode 的正確用法。這篇短文并不能保證你可以永遠(yuǎn)杜絕上面兩個(gè)錯(cuò)誤,但是希望在下次遇到這個(gè)錯(cuò)誤的時(shí)候知道錯(cuò)在哪里、應(yīng)該從哪里入手。

編碼與解碼

上面的兩個(gè)錯(cuò)誤分別是 UnicodeEncodeErrorUnicodeDecodeError,也就是說(shuō)分別在 Unicode 編碼(Encode)和解碼(Decode)過(guò)程中出現(xiàn)了錯(cuò)誤,那么編碼和解碼究竟分別意味著什么?根據(jù)維基百科字符編碼的定義:

字符編碼(英語(yǔ):Character encoding)、字集碼是把字符集中的字符編碼為指定集合中某一對(duì)象(例如:比特模式、自然數(shù)序列、8位組或者電脈沖),以便文本在計(jì)算機(jī)中存儲(chǔ)和通過(guò)通信網(wǎng)絡(luò)的傳遞。

簡(jiǎn)單來(lái)說(shuō)就是把人類通用的語(yǔ)言符號(hào)翻譯成計(jì)算機(jī)通用的對(duì)象,而反向的翻譯過(guò)程自然就是解碼了。Python 中的字符串類型代表人類通用的語(yǔ)言符號(hào),因此字符串類型有encode()方法;而字節(jié)類型代表計(jì)算機(jī)通用的對(duì)象(二進(jìn)制數(shù)據(jù)),因此字節(jié)類型有decode()方法。

print("??".encode())
b"xf0x9fx8cx8exf0x9fx8cx8f"
print(b"xf0x9fx8cx8exf0x9fx8cx8f".decode())
??

既然說(shuō)編碼和解碼都是翻譯的過(guò)程,那么就需要一本字典將人類和計(jì)算機(jī)的語(yǔ)言一一對(duì)應(yīng)起來(lái),這本字典的名字叫做字符集,從最早的 ASCII 到現(xiàn)在最通用的 Unicode,它們的本質(zhì)是一樣的,只是兩本字典的厚度不同而已。ASCII 只包含了26個(gè)基本拉丁字母、阿拉伯?dāng)?shù)目字和英式標(biāo)點(diǎn)符號(hào)一共128個(gè)字符,因此只需要(不占滿)一個(gè)字節(jié)就可以存儲(chǔ),而 Unicode 則涵蓋的數(shù)據(jù)除了視覺(jué)上的字形、編碼方法、標(biāo)準(zhǔn)的字符編碼外,還包含了字符特性,如大小寫字母,共可包含 1.1M 個(gè)字符,而到現(xiàn)在只填充了其中的 110K 個(gè)位置。

字符集中字符所存儲(chǔ)的位置(或者說(shuō)對(duì)應(yīng)的計(jì)算機(jī)通用的數(shù)字)稱之為碼位(code point),例如在 ASCII 中字符 "$" 的碼位就是:

print(ord("$"))
36

ASCII 只需要一個(gè)字節(jié)就能存下所有碼位,而 Unicode 則需要幾個(gè)字節(jié)才能容納,但是對(duì)于具體采用什么樣的方案來(lái)實(shí)現(xiàn) Unicode 的這種映射關(guān)系,也有很多不同的方案(或規(guī)則),例如最常見(jiàn)(也是 Python 中默認(rèn)的)UTF-8,還有 UTF-16、UTF-32 等,對(duì)于它們規(guī)則上的不同這里就不深入展開(kāi)了。當(dāng)然,在 ASCII 與 Unicode 之間還有很多其他的字符集與編碼方案,例如中文編碼的 GB2312、繁體字的 Big5 等等,這并不影響我們對(duì)編碼與解碼過(guò)程的理解。

Unicode*Error

明白了字符串與字節(jié),編碼與解碼之后,讓我們手動(dòng)制造上面兩個(gè) Unicode*Error 試試,首先是編碼錯(cuò)誤:

def tryEncode(s, encoding="utf-8"):
    try:
        print(s.encode(encoding))
    except UnicodeEncodeError as err:
        print(err)
    
s = "$"           # UTF-8 String
tryEncode(s)          # 默認(rèn)用 UTF-8 進(jìn)行編碼
tryEncode(s, "ascii") # 嘗試用 ASCII 進(jìn)行編碼

s = "雨"          # UTF-8 String
tryEncode(s)          # 默認(rèn)用 UTF-8 進(jìn)行編碼
tryEncode(s, "ascii") # 嘗試用 ASCII 進(jìn)行編碼
tryEncode(s, "GB2312")  # 嘗試用 GB2312 進(jìn)行編碼
b"$"
b"$"
b"xe9x9bxa8"
"ascii" codec can"t encode character "u96e8" in position 0: ordinal not in range(128)
b"xd3xea"

由于 UTF-8 對(duì) ASCII 的兼容性,"$" 可以用 ASCII 進(jìn)行編碼;而 "雨" 則無(wú)法用 ASCII 進(jìn)行編碼,因?yàn)樗呀?jīng)超出了 ASCII 字符集的 128 個(gè)字符,所以引發(fā)了 UnicodeEncodeError;而 "雨" 在 GB2312 中的碼位是 b"xd3xea",與 UTF-8 不同,但是仍然可以正確編碼。因此如果出現(xiàn)了 UnicodeEncodeError 說(shuō)明你用錯(cuò)了字典,要翻譯的字符沒(méi)辦法正確翻譯成碼位!

再來(lái)看解碼錯(cuò)誤:

def tryDecode(s, decoding="utf-8"):
    try:
        print(s.decode(decoding))
    except UnicodeDecodeError as err:
        print(err)
        
b = b"$"     # Bytes
tryDecode(b)          # 默認(rèn)用 UTF-8 進(jìn)行解碼
tryDecode(b, "ascii") # 嘗試用 ASCII 進(jìn)行解碼
tryDecode(b, "GB2312") # 嘗試用 GB2312 進(jìn)行解碼

b = b"xd3xea" # 上面例子中通過(guò) GB2312 編碼得到的 Bytes
tryDecode(b)           # 默認(rèn)用 UTF-8 進(jìn)行解碼
tryDecode(b, "ascii")  # 嘗試用 ASCII 進(jìn)行解碼
tryDecode(b, "GB2312") # 嘗試用 GB2312 進(jìn)行解碼
tryDecode(b, "GBK")    # 嘗試用 GBK 進(jìn)行解碼
tryDecode(b, "Big5")    # 嘗試用 Big5 進(jìn)行解碼

tryDecode(b.decode("GB2312").encode()) # Byte-Decode-Unicode-Encode-Byte
$
$
$
"utf-8" codec can"t decode byte 0xd3 in position 0: invalid continuation byte
"ascii" codec can"t decode byte 0xd3 in position 0: ordinal not in range(128)
雨
雨
迾
雨

一般后續(xù)出現(xiàn)的字符集都是對(duì) ASCII 兼容的,可以認(rèn)為 ASCII 是他們的一個(gè)子集,因此可以用 ASCII 進(jìn)行解碼(編碼)的,一般也可以用其它方法;對(duì)于不是不存在子集關(guān)系的編碼,強(qiáng)行解碼有可能會(huì)導(dǎo)致錯(cuò)誤或亂碼!

實(shí)踐中的策略

清楚了上面介紹的所有原理之后,在時(shí)間操作中應(yīng)該怎樣規(guī)避錯(cuò)誤或亂碼呢?

記清楚編碼與解碼的方向;

在 Python 中的操作盡量采用 UTF-8,輸入或輸出的時(shí)候再根據(jù)需求確定是否需要編碼成二進(jìn)制:

# cat utf8.txt
# 你好,世界!
# file utf8.txt
# utf8.txt: UTF-8 Unicode text

with open("utf8.txt", "rb") as f:
    content = f.read()
    print(content)
    print(content.decode())
with open("utf8.txt", "r") as f:
    print(f.read())
    
# cat gb2312.txt
# 你好,Unicode!
# file gb2312.txt
# gb2312.txt: ISO-8859 text

with open("gb2312.txt", "r") as f:
    try:
        print(f.read())
    except:
        print("Failed to decode file!")
with open("gb2312.txt", "rb") as f:
    print(f.read().decode("gb2312"))
b"xe4xbdxa0xe5xa5xbdxefxbcx8cxe4xb8x96xe7x95x8cxefxbcx81
"
你好,世界!

你好,世界!

Failed to decode file!
你好,Unicode!


歡迎關(guān)注 PyHub!

參考

Pragmatic Unicode

字符編碼筆記:ASCII,Unicode和UTF-8

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/37832.html

相關(guān)文章

  • PyTips 0x08 - Python 字節(jié)與字節(jié)數(shù)組

    摘要:回到對(duì)字節(jié)和字節(jié)數(shù)組的定義為了用計(jì)算機(jī)可以理解的數(shù)字描述人類使用的字符,我們需要一張數(shù)字與字符對(duì)應(yīng)的表。由于和字符串一樣是序列類型,字節(jié)和字節(jié)數(shù)組可用的方法也類似,這里就不一一列舉了。 項(xiàng)目地址:https://git.io/pytips 0x07 中介紹了 Python 中的字符串類型,字符串類型是對(duì)人類友好的符號(hào),但計(jì)算機(jī)只認(rèn)識(shí)一種符號(hào),那就是二進(jìn)制(binary)數(shù),或者說(shuō)是數(shù)字...

    Leo_chen 評(píng)論0 收藏0
  • PyTips 0x07 - Python 字符串

    摘要:項(xiàng)目地址所有用過(guò)的人應(yīng)該都看過(guò)下面兩行錯(cuò)誤信息這就是界的錕斤拷今天和接下來(lái)幾期的內(nèi)容將主要關(guān)注中的字符串字節(jié)及兩者之間的相互轉(zhuǎn)換。 項(xiàng)目地址:https://git.io/pytips 所有用過(guò) Python (2&3)的人應(yīng)該都看過(guò)下面兩行錯(cuò)誤信息: UnicodeEncodeError: ascii codec cant encode characters in position...

    go4it 評(píng)論0 收藏0
  • PyTips 0x15 - Python `__future__` 模塊

    摘要:模塊的導(dǎo)入一定要放在最上方,也就是在所有其它模塊之前導(dǎo)入。最后一列是每個(gè)新特性所對(duì)應(yīng)的及簡(jiǎn)單描述。相對(duì)導(dǎo)入則可以使用為標(biāo)記導(dǎo)入相對(duì)目錄中的模塊,具體可以參考這篇文章導(dǎo)入模塊的幾種姿勢(shì)。 項(xiàng)目地址:https://git.io/pytips 我們經(jīng)常從一些組織良好的 Python 項(xiàng)目中看到 __future__ 的身影,例如: from __future__ import absolu...

    klinson 評(píng)論0 收藏0
  • PyTips 0x0b - Python 無(wú)處不在else

    摘要:可以通過(guò)一個(gè)簡(jiǎn)單的例子來(lái)展示當(dāng)然,也可以用狀態(tài)變量的做法來(lái)替代總結(jié)有人覺(jué)得的這些用法違反直覺(jué)或者是而非,不值得提倡。 項(xiàng)目地址:https://git.io/pytips 我們都知道 Python 中 else 的基本用法是在條件控制語(yǔ)句中的 if...elif...else...,但是 else 還有兩個(gè)其它的用途,一是用于循環(huán)的結(jié)尾,另一個(gè)是用在錯(cuò)誤處理的 try 中。這原本是 P...

    jaysun 評(píng)論0 收藏0
  • PyTips 0x17-Python 枚舉類型

    摘要:中的枚舉類型枚舉類型可以看作是一種標(biāo)簽或是一系列常量的集合,通常用于表示某些特定的有限集合,例如星期月份狀態(tài)等。 Python 中的枚舉類型 枚舉類型可以看作是一種標(biāo)簽或是一系列常量的集合,通常用于表示某些特定的有限集合,例如星期、月份、狀態(tài)等。Python 的原生類型(Built-in types)里并沒(méi)有專門的枚舉類型,但是我們可以通過(guò)很多方法來(lái)實(shí)現(xiàn)它,例如字典、類等: WEEKD...

    yedf 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<