摘要:每個(gè)字符都可以編碼為唯一的序列。但在中還有其他的數(shù)字系統(tǒng),通過其他方式是表示數(shù)字。事實(shí)上,是的完美子集。里的編碼與解碼的類型用于表示人類可讀的文本,可以包含任何字符。編碼的文本表示為二進(jìn)制數(shù)據(jù)字節(jié)。
概述
在使用Python或者其他的編程語言,都會多多少少遇到編碼錯(cuò)誤,處理起來非常痛苦。在Stack Overflow和其他的編程問答網(wǎng)站上,UnicodeDecodeError和UnicodeEncodeError也經(jīng)常被提及。本篇教程希望能幫你認(rèn)識Python編碼,并能夠從容的處理編碼問題。
本教程提到的編碼知識并不限定在Python,其他語言也大同小異,但我們依然會以Python為主,來演示和講解編碼知識。
通過該教程,你將學(xué)習(xí)到如下的知識:
獲取有關(guān)字符編碼和數(shù)字系統(tǒng)的概念
理解編碼如何使用Python的str和bytes
通過int函數(shù)了解Python對數(shù)字系統(tǒng)的支持
熟悉Python字符編碼和數(shù)字系統(tǒng)相關(guān)的內(nèi)置函數(shù)
什么是字符編碼現(xiàn)在的編碼規(guī)則已經(jīng)有好多了,最簡單、最基本是的ASCII編碼,只要是你學(xué)過計(jì)算機(jī)相關(guān)的課程,你就應(yīng)該多少了解一點(diǎn)ASCII編碼,他是最小也是最適合了解字符編碼原理的編碼規(guī)則。具體如下:
小寫英文字符:a-z
大寫英文字符:A-Z
符號: 比如 $和!
空白符:回車、換行、空格等
一些不可打印的字符: 比如b等
那么,字符編碼的定義到底是什么了?它是一種將字符(如字母,標(biāo)點(diǎn)符號,符號,空格和控制字符)轉(zhuǎn)換為整數(shù)并最終轉(zhuǎn)換為bit進(jìn)行存儲的方法。 每個(gè)字符都可以編碼為唯一的bit序列。 如果你對bit的概念不了解,請不要擔(dān)心,我們后面會介紹。
ASCII碼的字符被分為如下幾組:
ASCII表一共包括128個(gè)字符,如果你想了解整個(gè)ASCII表,這里有
大家在學(xué)python的時(shí)候肯定會遇到很多難題,以及對于新技術(shù)的追求,這里推薦一下我們的Python學(xué)習(xí)扣qun:784,758,214,這里是python學(xué)習(xí)者聚集地
Python string模塊string模塊是python里處理字符串很方便的模塊,它包括了整個(gè)ASCII字符,讓我們來看看部分string模塊源碼:
# From lib/python3.7/string.py whitespace = " vf" ascii_lowercase = "abcdefghijklmnopqrstuvwxyz" ascii_uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ascii_letters = ascii_lowercase + ascii_uppercase digits = "0123456789" hexdigits = digits + "abcdef" + "ABCDEF" octdigits = "01234567" punctuation = r"""!"#$%&"()*+,-./:;<=>?@[]^_`{|}~""" printable = digits + ascii_letters + punctuation + whitespace
你可以在Python中這樣使用string模塊:
>>> import string >>> s = "What"s wrong with ASCII?!?!?" >>> s.rstrip(string.punctuation) "What"s wrong with ASCII"什么是bit
學(xué)過計(jì)算機(jī)相關(guān)課程的同學(xué),應(yīng)該都知道,bit是計(jì)算機(jī)內(nèi)部存儲單位,只有0和1兩個(gè)狀態(tài)(二進(jìn)制),我們上面所說的ASCII表,都是一個(gè)10進(jìn)制的數(shù)字表示一個(gè)字符,而這個(gè)10進(jìn)制數(shù)字,最終會轉(zhuǎn)換成0和1,存儲在計(jì)算機(jī)內(nèi)部。例如(第一列是10進(jìn)制數(shù)字,第二列是二進(jìn)制,第三列是計(jì)算機(jī)內(nèi)部存儲結(jié)果):
這是一種在Python中將ASCII字符串表示為位序列的方便方法。 ASCII字符串中的每個(gè)字符都被偽編碼為8位,8位序列之間有空格,每個(gè)字符代表一個(gè)字符:
>>> def make_bitseq(s: str) -> str: ... if not s.isascii(): ... raise ValueError("ASCII only allowed") ... return " ".join(f"{ord(i):08b}" for i in s) >>> make_bitseq("bits") "01100010 01101001 01110100 01110011" >>> make_bitseq("CAPS") "01000011 01000001 01010000 01010011" >>> make_bitseq("$25.43") "00100100 00110010 00110101 00101110 00110100 00110011" >>> make_bitseq("~5") "01111110 00110101"
我們也可以是用python的f-string 來格式化,比如f"{ord(i):08b}":
冒號的左側(cè)是ord(i),它是實(shí)際的對象,其值將被格式化并插入到輸出中。 使用ord()為單個(gè)str字符提供了base-10代碼點(diǎn)。
冒號的右側(cè)是格式說明符。 08表示寬度為8,0填充,b用作在基數(shù)2(二進(jìn)制)中輸出結(jié)果數(shù)的符號。
ASCII編碼不夠用了ASCII采用的是8bit來存儲字符(只使用7位,剩下的1位二進(jìn)制為0),所以,ASCII最多存儲128個(gè)字符,這有個(gè)簡單的公式,計(jì)算存儲字符的bit數(shù)量與存儲字符總數(shù)的關(guān)系:2的n次方,n表示bit數(shù)量。例如:
1bit存儲2個(gè)字符
8bit存儲256個(gè)字符
64bit存儲2的64次方 == 18,446,744,073,709,551,616
我們可以寫個(gè)簡單的代碼,來計(jì)算一下,指定字符數(shù)量,至少需要多少bit來存儲:
>>> from math import ceil, log >>> def n_bits_required(nvalues: int) -> int: ... return ceil(log(nvalues) / log(2)) >>> n_bits_required(256) 8數(shù)字系統(tǒng)
在上面的ASCII討論中,您看到每個(gè)字符映射到0到127范圍內(nèi)的整數(shù)。但在CPython中還有其他的數(shù)字系統(tǒng),通過其他方式是表示數(shù)字。除了十進(jìn)制外,python還支持以下幾個(gè)方式:
Binary: 2進(jìn)制
Octal: 8進(jìn)制
Hexadecimal (hex): 16進(jìn)制
你可能要問,為什么有了十進(jìn)制,還要支持這么多其他進(jìn)制的數(shù)字了?這個(gè)取決你的業(yè)務(wù)場景和操作系統(tǒng),在Python里,把str轉(zhuǎn)換成int,默認(rèn)是10進(jìn)制的。
>>> int("11") 11 >>> int("11", base=10) # 10 is already default 11 >>> int("11", base=2) # Binary 3 >>> int("11", base=8) # Octal 9 >>> int("11", base=16) # Hex 17
你可以在賦值時(shí),直接告訴解釋器數(shù)字的類型,不同進(jìn)制標(biāo)表示方法如下:
類型 | 前綴 | 示例 |
---|---|---|
n/a | n/a | 11 |
二進(jìn)制 | 0b 或者 0B | 0b11 |
八進(jìn)制 | 0o 或者 0O | 0o11 |
十六進(jìn)制 | 0x 或者 0X | 0x11 |
>>> 11 11 >>> 0b11 # 二進(jìn)制 3 >>> 0o11 # 八進(jìn)制 9 >>> 0x11 # 16進(jìn)制 17深入U(xiǎn)nicode
正如您所看到的,ASCII的問題在于它不是一個(gè)足夠大的字符集來容納世界上的語言,方言,符號和字形。 (這對于英語來說甚至都不夠大。)Unicode從根本上起到與ASCII相同的作用,但是Unicode擁有更大的存儲空間,具有1,114,112個(gè)可能的字符,能夠完全包含世界上所有的語言。事實(shí)上,ASCII是Unicode的完美子集。 Unicode表中的前128個(gè)字符與您合理期望的ASCII字符完全對應(yīng)。
Unicode本身不是編碼,但是有很多遵循Unicode編碼規(guī)范編碼,后面講到的UTF-8就是其中一個(gè)。
Unicode vs UTF-8Unicode是一種抽象編碼標(biāo)準(zhǔn),而不是編碼。這就是UTF-8和其他編碼方案發(fā)揮作用的地方。 Unicode標(biāo)準(zhǔn)(字符到代碼點(diǎn)的映射)從其單個(gè)字符集定義了幾種不同的編碼。UTF-8及其較少使用的表兄弟UTF-16和UTF-32是用于將Unicode字符表示為每個(gè)字符一個(gè)或多個(gè)字節(jié)的二進(jìn)制數(shù)據(jù)的編碼格式。我們稍后將討論UTF-16和UTF-32,但到目前為止,UTF-8占據(jù)了最大份額。
Python 3里的編碼與解碼Python 3的str類型用于表示人類可讀的文本,可以包含任何Unicode字符。
相反,字節(jié)類型表示二進(jìn)制數(shù)據(jù)或原始字節(jié)序列,它們本質(zhì)上沒有附加編碼。
編碼和解碼是從一個(gè)到另一個(gè)的過程:
decode 和 encode 函數(shù),默認(rèn)編碼是utf-8:
>>> "résumé".encode("utf-8") b"rxc3xa9sumxc3xa9" >>> "El Ni?o".encode("utf-8") b"El Nixc3xb1o" >>> b"rxc3xa9sumxc3xa9".decode("utf-8") "résumé" >>> b"El Nixc3xb1o".decode("utf-8") "El Ni?o"
str.encode()的結(jié)果是一個(gè)bytes對象,bytes對象只允許ASCII字符。這就是為什么在調(diào)用“ElNi?o”.encode(“utf-8”)時(shí),允許ASCII兼容的“El”按原樣表示,但帶有波浪號的n被轉(zhuǎn)義為“ xc3 xb1”。 這個(gè)看起來很亂的序列代表兩個(gè)字節(jié),十六進(jìn)制為0xc3和0xb1:
>>> " ".join(f"{i:08b}" for i in (0xc3, 0xb1)) "11000011 10110001"Python3一切字符皆Unicode
默認(rèn)情況下,Python 3源代碼假定為UTF-8。 這意味著您不需要# - - 編碼:UTF-8 - - 位于Python 3中.py文件的頂部。
默認(rèn)情況下,所有文本(str)都是Unicode。 編碼的Unicode文本表示為二進(jìn)制數(shù)據(jù)(字節(jié))。 str類型可以包含任何文字Unicode字符,例如“Δv/Δt”,所有這些字符都將存儲為Unicode。
Unicode字符集中的任何內(nèi)容都是標(biāo)識符中的猶太符號,這意味著résumé=“?/ Documents / resume.pdf”是有效的,雖然這看起來很花哨。
Python的re模塊默認(rèn)為re.UNICODE標(biāo)志而不是re.ASCII。 這意味著,例如,r“ w”匹配Unicode字符,而不僅僅是ASCII字母。
str.encode()和bytes.decode()中的默認(rèn)編碼是UTF-8。
還有一個(gè)更細(xì)微的屬性,即內(nèi)置的open()的默認(rèn)編碼是依賴于平臺的,并且取決于locale.getpreferredencoding()的值:
>>> # Mac OS X High Sierra >>> import locale >>> locale.getpreferredencoding() "UTF-8" >>> # Windows Server 2012; other Windows builds may use UTF-16 >>> import locale >>> locale.getpreferredencoding() "cp1252"
一個(gè)關(guān)鍵特性是UTF-8是一種可變長度編碼?;叵胍幌玛P(guān)于ASCII的部分。 擴(kuò)展ASCII-land中的所有內(nèi)容最多需要一個(gè)字節(jié)的空間。 您可以使用以下生成器表達(dá)式快速證明這一點(diǎn):
>>> all(len(chr(i).encode("ascii")) == 1 for i in range(128)) True
UTF-8完全不同。 給定的Unicode字符可以占用1到4個(gè)字節(jié)。 以下是占用四個(gè)字節(jié)的單個(gè)Unicode字符的示例:
>>> ibrow = "
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/43997.html
摘要:每個(gè)字符都可以編碼為唯一的序列。但在中還有其他的數(shù)字系統(tǒng),通過其他方式是表示數(shù)字。事實(shí)上,是的完美子集。里的編碼與解碼的類型用于表示人類可讀的文本,可以包含任何字符。編碼的文本表示為二進(jìn)制數(shù)據(jù)字節(jié)。 概述 在使用Python或者其他的編程語言,都會多多少少遇到編碼錯(cuò)誤,處理起來非常痛苦。在Stack Overflow和其他的編程問答網(wǎng)站上,UnicodeDecodeError和Unic...
摘要:相信很多人在格式化字符串的時(shí)候都用的語法,提出一種更先進(jìn)的格式化方法并成為的標(biāo)準(zhǔn)用來替換舊的格式化語法,從開始已經(jīng)實(shí)現(xiàn)了這一方法其它解釋器未考證。 showImg(https://segmentfault.com/img/remote/1460000018650325); 相信很多人在格式化字符串的時(shí)候都用%s % v的語法,PEP 3101 提出一種更先進(jìn)的格式化方法 str.for...
摘要:最近使用處理一些網(wǎng)絡(luò)相關(guān)的問題,被相關(guān)的一系列編碼問題搞得一頭霧水。與接下來是中對于字符串的處理。中的和在中,其類型規(guī)定了底層的數(shù)據(jù)結(jié)構(gòu),是位整數(shù)串,也即跟語言中的字符串類似。這些問題在中得到解決。 最近使用 Python 2 處理一些網(wǎng)絡(luò)相關(guān)的問題,被 Unicode, String 相關(guān)的一系列編碼問題搞得一頭霧水。在這里整理一下相關(guān)的概念吧。 ASCII Unicode UTF8...
摘要:使用進(jìn)行并發(fā)編程篇三掘金這是使用進(jìn)行并發(fā)編程系列的最后一篇。所以我考慮啟用一個(gè)本地使用進(jìn)行并發(fā)編程篇二掘金我們今天繼續(xù)深入學(xué)習(xí)。 使用 Python 進(jìn)行并發(fā)編程 - asyncio 篇 (三) - 掘金 這是「使用Python進(jìn)行并發(fā)編程」系列的最后一篇。我特意地把它安排在了16年最后一天。 重新實(shí)驗(yàn)上篇的效率對比的實(shí)現(xiàn) 在第一篇我們曾經(jīng)對比并發(fā)執(zhí)行的效率,但是請求的是httpb...
摘要:縮進(jìn)不一致,會導(dǎo)致運(yùn)行錯(cuò)誤。變量變量在使用前必須先定義即賦予變量一個(gè)值,否則會報(bào)錯(cuò)數(shù)據(jù)類型布爾只有和兩個(gè)值,表示真或假。 簡介 Python 是一種高層次的結(jié)合了解釋性、編譯性、互動性和面向?qū)ο蟮哪_本語言。Python 由 Guido van Rossum 于 1989 年底在荷蘭國家數(shù)學(xué)和計(jì)算機(jī)科學(xué)研究所發(fā)明,第一個(gè)公開發(fā)行版發(fā)行于 1991 年。 特點(diǎn) 易于學(xué)習(xí):Python ...
閱讀 2894·2021-11-24 09:39
閱讀 3151·2021-11-19 10:00
閱讀 1552·2021-10-27 14:17
閱讀 1821·2021-10-14 09:43
閱讀 977·2021-09-03 10:30
閱讀 3421·2019-08-30 15:54
閱讀 2748·2019-08-30 13:05
閱讀 2021·2019-08-30 11:02