日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
一籌莫展?來看看字符編碼的前世今生吧

前言

很多程序員對字符編碼不太理解,雖然他們大概知道 ASCII、UTF8、GBK、Unicode 等術(shù)語概念,但在寫代碼過程中還是會遇到各種奇怪的編碼問題,在 Java 中最常見的是亂碼,而 Python 開發(fā)中遇到最多的是編碼錯誤,如:UnicodeDecodeError、UnicodeEncodeError,幾乎每個 Python 開發(fā)者都會碰到這種問題,對此都是一籌莫展,這篇文章從字符編碼的起源開始,講述了編程中應(yīng)該如何應(yīng)對編碼的問題,通過理解本文,你可以從容地定位、分析、解決字符編碼相關(guān)的問題。

說到「字符編碼」我們先要理解什么是編碼以及為什么要編碼。

什么是編碼

但凡學(xué)過計算機的同學(xué)都知道,計算機只能處理0和1組成的二進制數(shù)據(jù),人類借助計算機所看到的、聽到的任何信息,包括:文本、視頻、音頻、圖片在計算機中都是以二進制形式進行存儲和運算。計算機善于處理二進制數(shù)據(jù),但是人類對于二進制數(shù)據(jù)顯得捉襟見肘,為了降低人與計算機的交流成本,人們決定把每個字符進行編號,比如給字母 A 的編號是 65,對應(yīng)的二進制數(shù)是「01000001」,當把 A 存到計算機中時就用 01000001 來代替,當要加載顯示在文件中或網(wǎng)頁中用來閱覽時,就把二進制數(shù)轉(zhuǎn)換成字符 A,這個過程中就會涉及到不同格式數(shù)據(jù)之間的轉(zhuǎn)換。

編碼(encode)是把數(shù)據(jù)從一種形式轉(zhuǎn)換為另外一種形式的過程,它是一套算法,比如這里的字符 A 轉(zhuǎn)換成 01000001 就是一次編碼的過程,解碼(decode)就是編碼的逆過程。今天我們討論的是關(guān)于字符的編碼,是字符和二進制數(shù)據(jù)之間轉(zhuǎn)換的算法。密碼學(xué)中的加密解密有時也稱為編碼與解碼,不過它不在本文討論范圍內(nèi)。

什么是字符集

字符集是一個系統(tǒng)支持的所有抽象字符的集合。它是各種文字和符號的總稱,常見的字符集種類包括 ASCII 字符集、GBK 字符集、Unicode字符集等。不同的字符集規(guī)定了有限個字符,比如:ASCII 字符集只含有拉丁文字字母,GBK 包含了漢字,而 Unicode 字符集包含了世界上所有的文字符號。

有人不禁要問,字符集與字符編碼是什么關(guān)系?別急,先往下面

ASCII:字符集與字符編碼的起源

世界上第一臺計算機,1945年由美國賓夕法尼亞大學(xué)的兩位教授-莫奇利和??颂卦O(shè)計和研制出來,美國人起草了計算機的第一份字符集和編碼標準,叫 ASCII(American Standard Code for Information Interchange,美國信息交換標準代碼),一共規(guī)定了 128 個字符及對應(yīng)的二進制轉(zhuǎn)換關(guān)系,128 個字符包括了可顯示的26個字母(大小寫)、10個數(shù)字、標點符號以及特殊的控制符,也就是英語與西歐語言中常見的字符,這128個字符用一個字節(jié)來表示綽綽有余,因為一個字節(jié)可以表示256個字符,所以當前只利用了字節(jié)的7位,最高位用來當作奇偶校驗。如下圖所以,字符小寫 a 對應(yīng) 01100001,大寫 A 對應(yīng) 01000001。

ASCII 字符集是字母、數(shù)字、標點符號以及控制符(回車、換行、退格)等組成的128個字符。ASCII 字符編碼是將這128個字符轉(zhuǎn)換為計算機可識別的二進制數(shù)據(jù)的一套規(guī)則(算法)?,F(xiàn)在可以回答前面的那個問題了,通常來說,字符集同時定義了一套同名的字符編碼規(guī)則,例如 ASCII 就定義了字符集以及字符編碼,當然這不是絕對的,比如 Unicode 就只定義了字符集,而對應(yīng)的字符編碼是 UTF-8,UTF-16。

ASCII 由美國國家標準學(xué)會制定,1967年定案,最初是美國國家標準,后來被國際標準化組織(International Organization for Standardization, ISO)定為國際標準,稱為ISO 646標準,適用于所有拉丁文字字母。

EASCII:擴展的ASCII

隨著計算機的不斷普及,計算機開始被西歐等國家使用,然后西歐語言中還有很多字符不在 ASCII 字符集中,這給他們使用計算機造成了很大的限制,就好比在中國,你只能用英語跟人家交流一樣。于是乎,他們想著法子把 ASCII 字符集進行擴充,以為 ASCII 只使用了字節(jié)的前 7 位,如果把第八位也利用起來,那么可表示的字符個數(shù)就是 256。這就是后來的 EASCII(Extended ASCII,延伸美國標準信息交換碼)EASCII 碼比 ASCII 碼擴充出來的符號包括表格符號、計算符號、希臘字母和特殊的拉丁符號。

然后 EASCII 并沒有形成統(tǒng)一的標準,各國個商家都有自己的小算盤,都想在字節(jié)的高位做文章,比如 MS-DOS, IBM PC上使用了各自定義的編碼字符集,為了結(jié)束這種混亂的局面,國際標準化組織(ISO)及國際電工委員會(IEC)聯(lián)合制定的一系列8位元字符集的標準,叫 ISO 8859,全稱ISO/IEC 8859,它在 ASCII 基礎(chǔ)之上擴展而來,所以完全 ASCII,ISO 8859 字符編碼方案所擴展的這128個編碼中,只有0xA0~0xFF(十進制為160~255)被使用,其實 ISO 8859是一組字符集的總稱,旗下共包含了15個字符集,分別是 ISO 8859-1 ~ ISO 8859-15,ISO 8859-1 又稱之為 Latin-1,它是西歐語言,其它的分別代表 中歐、南歐、北歐等字符集。

GB2312:滿足國人需求的字符集

后來,計算機開始普及到了中國,但面臨的一個問題就是字符,漢字博大精深,常用漢字有3500個,已經(jīng)大大超出了 ASCII 字符集所能表示的字符范圍了,即使是 EASCII 也顯得杯水車薪,1981 年國家標準化管理委員會定了一套字符集叫 GB2312,每個漢字符號由兩個字節(jié)組成,理論上它可以表示65536個字符,不過它只收錄了7445個字符,6763個漢字和682個其他字符,同時它能夠兼容 ASCII,ASCII 中定義的字符只占用一個字節(jié)的空間。

GB2312 所收錄的漢字已經(jīng)覆蓋中國大陸99.75%的使用頻率,但是對一些罕見的字和繁體字還有很多少數(shù)民族使用的字符都沒法處理,于是后來就在 GB2312 的基礎(chǔ)上創(chuàng)建了一種叫 GBK 的字符編碼,GBK 不僅收錄了27484 個漢字,同時還收錄了藏文、蒙文、維吾爾文等主要的少數(shù)民族文字。GBK 是利用了 GB2312 中未被使用的編碼空間上進行擴充,所以它能完全兼容 GB2312和 ASCII。而 GB 18030 是現(xiàn)時最新的字符集,兼容 GB 2312-1980 和 GBK, 共收錄漢字70244個,采用多字節(jié)編碼,每個字符可以有1、2、4個字節(jié)組成,某種意義上它能容納161 萬個字符,包含繁體漢字以及日韓漢字,單字節(jié)與ASCII兼容,雙字節(jié)與GBK標準兼容。

Unicode :統(tǒng)一江湖的字符集

盡管我們有了屬于自己的字符集和字符編碼 GBK,可世界上還有很多國家擁有自己的語言和文字,比如日本用 JIS,臺灣用 BIG5,不同國家之間交流起來就很困難,因為沒有統(tǒng)一的編碼標準,可能同一個字符,在A國家用兩字字節(jié)存儲,而到了B國家是3個字節(jié),這樣很容易出現(xiàn)編碼問題,于是在 1991 年,國際標準化組織和統(tǒng)一碼聯(lián)盟組織各自開發(fā)了 ISO/IEC 10646(USC)和 Unicode 項目,這兩個項目的目的都是希望用一種字符集來統(tǒng)一全世界所有字符,不過很快雙方都意識到世界上并不需要兩個不兼容的字符集。于是他們就編碼問題進行了非常友好地會晤,決定彼此把工作內(nèi)容合并,雖然項目還是獨立存在,各自發(fā)布各自的標準,但前提是兩者必須保持兼容。不過由于 Unicode 這一名字比較好記,因而它使用更為廣泛,成為了事實上的統(tǒng)一編碼標準。

以上是對字符集歷史的一個簡要回顧,現(xiàn)在重點來說說Unicode,Unicode 是一個囊括了世界上所有字符的字符集,其中每一個字符都對應(yīng)有唯一的編碼值(code point),注意了!它不是字符編碼,僅僅是字符集而已,Unicode 字符如何進行編碼,可以是 UTF-8、UTF-16、甚至用 GBK 來編碼。例如:

 
 
 
 
  1. >>> a = u"好"
  2. >>> a
  3. u'\u597d'
  4. >>> b = a.encode("utf-8")
  5. >>> b
  6. '\xe5\xa5\xbd'
  7. >>>
  8. >>> b = a.encode("gbk")
  9. >>> b
  10. '\xba\xc3'

Unicode 本身并沒有規(guī)定一個字符究竟是用一個還是三個或者四個字節(jié)表示。Unicode 只規(guī)定了每個字符對應(yīng)到唯一的代碼值(code point),代碼值 從 0000 ~ 10FFFF 共 1114112 個值 ,真正存儲的時候需要多少個字節(jié)是由具體的編碼格式?jīng)Q定的。比如:字符 「A」用 UTF-8 的格式編碼來存儲就只占用1個字節(jié),用 UTF-16 就占用2個字節(jié),而用 UTF-32 存儲就占用4個字節(jié)。

UTF-8:Unicode編碼

UTF( Unicode Transformation Format)編碼 和 USC(Universal Coded Character Set) 編碼分別是 Unicode 、ISO/IEC 10646 編碼體系里面兩種編碼方式,UCS 分為 UCS-2 和 UCS-4,而 UTF 常見的種類有 UTF-8、UTF-16、UTF-32。因為 Unicode 與 USC 兩種字符集是相互兼容的,所以這幾種編碼格式也有著對應(yīng)的等值關(guān)系

UCS-2 使用兩個定長的字節(jié)來表示一個字符,UTF-16 也是使用兩個字節(jié),不過 UTF-16 是變長的(網(wǎng)上很多錯誤的說法說 UTF-16是定長的),遇到兩個字節(jié)沒法表示時,會用4個字節(jié)來表示,因此 UTF-16 可以看作是在 UCS-2 的基礎(chǔ)上擴展而來的。而 UTF-32 與 USC-4 是完全等價的,使用4個字節(jié)表示,顯然,這種方式浪費的空間比較多。

UTF-8 的優(yōu)勢是:它以單字節(jié)為單位用 1~4 個字節(jié)來表示一個字符,從首字節(jié)就可以判斷一個字符的UTF-8編碼有幾個字節(jié)。如果首字節(jié)以0開頭,肯定是單字節(jié)編碼,如果以110開頭,肯定是雙字節(jié)編碼,如果是1110開頭,肯定是三字節(jié)編碼,以此類推。除了單字節(jié)外,多字節(jié)UTF-8碼的后續(xù)字節(jié)均以10開頭。

1~4 字節(jié)的 UTF-8 編碼看起來是這樣的:

引用

 
 
 
 
  1. 0xxxxxxx 
  2. 110xxxxx 10xxxxxx 
  3. 1110xxxx 10xxxxxx 10xxxxxx 
  4. 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
  • 單字節(jié)可編碼的 Unicode 范圍:\u0000~\u007F(0~127)
  • 雙字節(jié)可編碼的 Unicode 范圍:\u0080~\u07FF(128~2047)
  • 三字節(jié)可編碼的 Unicode 范圍:\u0800~\uFFFF(2048~65535)
  • 四字節(jié)可編碼的 Unicode 范圍:\u10000~\u1FFFFF(65536~2097151)

UTF-8 兼容了 ASCII,在數(shù)據(jù)傳輸和存儲過程中節(jié)省了空間,其二是UTF-8 不需要考慮大小端問題。這兩點都是 UTF-16 的劣勢。不過對于中文字符,用 UTF-8 就要用3個字節(jié),而 UTF-16 只需2個字節(jié)。而UTF-16 的優(yōu)點是在計算字符串長度,執(zhí)行索引操作時速度會很快。Java 內(nèi)部使用 UTF-16 編碼方案。而 Python3 使用 UTF-8。UTF-8 編碼在互聯(lián)網(wǎng)領(lǐng)域應(yīng)用更加廣泛。

來看一張圖,下圖是Windows平臺保存文件時可選擇的字符編碼類型,你可以指定系統(tǒng)以什么樣的編碼格式來存儲文件,ANSI 是 ISO 8859-1的超集,之所以在 Windows下有 Unicode 編碼這樣一種說法,其實是 Windows 的一種錯誤表示方法,或許是因為歷史原因一直沿用至今,其實它真正表示的是 UTF-16 編碼,更具體一點是 UTF-16小端,什么是大端和小端呢?

大端與小端

大小端是數(shù)據(jù)在存儲器中的存放順序,大端模式,是指數(shù)據(jù)的高字節(jié)在前,保存在內(nèi)存的低地址中,與人類的讀寫法一致,數(shù)據(jù)的低字節(jié)在后,保存在內(nèi)存的高地址中,小端與之相反,小端模式,是指數(shù)據(jù)的高字節(jié)在后,保存在內(nèi)存的高地址中,而數(shù)據(jù)的低字節(jié)在前,保存在內(nèi)存的低地址中例如,十六進制數(shù)值 0x1234567 的大端字節(jié)序和小端字節(jié)序的寫法:

至于為什么會有大端和小端之分呢?對于 16 位或者 32 位的處理器,由于寄存器寬度大于一個字節(jié),那么必然存在著一個如何將多個字節(jié)排放的問題,因為不同操作系統(tǒng)讀取多字節(jié)的順序不一樣,,x86和一般的OS(如windows,F(xiàn)reeBSD,Linux)使用的是小端模式。但比如Mac OS是大端模式。因此就導(dǎo)致了大端存儲模式和小端存儲模式的存在,兩者并沒有孰優(yōu)孰劣。

為什么UTF-8不需要考慮大小端問題?

UTF-8 的編碼單元是1個字節(jié),所以就不用考慮字節(jié)序問題。而 UTF-16 是用 2個字節(jié)來編碼 Unicode 字符,編碼單位是兩個字節(jié),因此需要考慮字節(jié)序問題,因為2個字節(jié)哪個存高位哪個存低位需要確定。

Python2 中的字符編碼

現(xiàn)在總算把理論說完了,再來說說 Python 中的編碼問題,也是每個Python開發(fā)者最關(guān)心、最經(jīng)常遇到的問題,Python 的誕生時間比 Unicode 還要早幾年,所以,Python的第一個版本一直延續(xù)到Python2.7,Python 的默認編碼都是 ASCII

 
 
 
 
  1. >>> import sys
  2. >>> sys.getdefaultencoding()
  3. 'ascii'

所以在 Python 源代碼,要能夠正常保存中文字符就必須先指定utf

8 或者 gbk 格式

 
 
 
 
  1. # coding=utf-8

或者是:

 
 
 
 
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-

在前面我們介紹過字符,這里還有必要重復(fù)一下字符和字節(jié)的區(qū)別,字符就是一個符號,比如一個漢字、一個字母、一個數(shù)字、一個標點都可以稱為一個字符,而字節(jié)就是字符就是編碼之后轉(zhuǎn)換而成的二進制序列,一個字節(jié)是8個比特位。例如字符 "p" 存儲到硬盤是一串二進制數(shù)據(jù) 01110000,占用一個字節(jié)。字節(jié)方便存儲和網(wǎng)絡(luò)傳輸,而字符用于顯示方便閱讀。

在Python2中,字符與字節(jié)的表示很微妙,兩者的界限很模糊,Python2 中把字符串分為 unicode 和 str 兩種類型。本質(zhì)上 str 類型是二進制字節(jié)序列, unicode 類型的字符串是字符,下面的示例代碼可以看出 str 類型的 "禪" 打印出來是十六進制的 \xec\xf8 ,對應(yīng)的二進制字節(jié)序列就是 '11101100 11111000'。

 
 
 
 
  1. >>> s = '禪'
  2. >>> s
  3. '\xec\xf8'
  4. >>> type(s)

而 unicode 類型的 u"禪" 對應(yīng)的 unicode 符號是 u'\u7985'

 
 
 
 
  1. >>> u = u"禪"
  2. >>> u
  3. u'\u7985'
  4. >>> type(u)

我們要把 unicode 字符保存到文件或者傳輸?shù)骄W(wǎng)絡(luò)就需要經(jīng)過編碼處理轉(zhuǎn)換成二進制形式的 str 類型,于是 python 的字符串提供了 encode 方法,從 unicode 轉(zhuǎn)換到 str,反之亦然。

 
 
 
 
  1. >>> u = u"禪"
  2. >>> u
  3. u'\u7985'
  4. >>> u.encode("utf-8")
  5. '\xe7\xa6\x85'
  6. >>> s = "禪"
  7. >>> s.decode("utf-8")
  8. u'\u7985'
  9. >>>

不少初學(xué)者怎么也記不住 str 與 unicode 之間的轉(zhuǎn)換用 encode 還是 decode,如果你記住了 str 本質(zhì)上其實是一串二進制數(shù)據(jù),而 unicode 是字符(符號),編碼(encode)就是把字符(符號)轉(zhuǎn)換為 二進制數(shù)據(jù)的過程,因此 unicode 到 str 的轉(zhuǎn)換要用 encode 方法,反過來就是用 decode 方法。

引用

encoding always takes a Unicode string and returns a bytes sequence, and decoding always takes a bytes sequence and returns a Unicode string".

清楚了 str 與 unicode 之間的轉(zhuǎn)換關(guān)系之后,我們來看看什么時候會出現(xiàn) UnicodeEncodeError、UnicodeDecodeError 錯誤。

UnicodeEncodeError

UnicodeEncodeError 發(fā)生在 unicode 字符串轉(zhuǎn)換成 str 字節(jié)序列的時候,來看一個例子,把一串 unicode 字符串保存到文件

 
 
 
 
  1. # -*- coding:utf-8 -*-
  2. def main():
  3.     name = u'Python之禪'
  4.     f = open("output.txt", "w")
  5.     f.write(name)

錯誤日志

引用

  • UnicodeEncodeError: 'ascii' codec can't encode characters in position 6-7: ordinal not in range(128)

為什么會出現(xiàn) UnicodeEncodeError?

因為調(diào)用 write 方法時,程序會把字符經(jīng)過編碼轉(zhuǎn)換成二進制字節(jié)序列,內(nèi)部會有 unicode 到 str 的編碼轉(zhuǎn)換過程,程序會先判斷字符串是什么類型,如果是 str,就直接寫入文件,不需要編碼,因為 str 類型的字符串本身就是一串二進制的字節(jié)序列了。如果字符串是 unicode 類型,那么它會先調(diào)用 encode 方法把 unicode 字符串轉(zhuǎn)換成二進制形式的 str 類型,才保存到文件,而 Python2中,encode 方法默認使用 ascii 進行 encde.

相當于:

 
 
 
 
  1. >>> u"Python之禪".encode("ascii")

但是,我們知道 ASCII 字符集中只包含了128個拉丁字母,不包括中文字符,因此 出現(xiàn)了 'ascii' codec can't encode characters 的錯誤。要正確地使用 encode ,就必須指定一個包含了中文字符的字符集,比如:UTF-8、GBK。

 
 
 
 
  1. >>> u"Python之禪".encode("utf-8")
  2. 'Python\xe4\xb9\x8b\xe7\xa6\x85'
  3. >>> u"Python之禪".encode("gbk")
  4. 'Python\xd6\xae\xec\xf8'

所以要把 unicode 字符串正確地寫入文件,就應(yīng)該預(yù)先把字符串進行 UTF-8 或 GBK 編碼轉(zhuǎn)換。

 
 
 
 
  1. def main():
  2.     name = u'Python之禪'
  3.     name = name.encode('utf-8')
  4.     with open("output.txt", "w") as f:
  5.         f.write(name)

或者直接寫str類型的字符串

 
 
 
 
  1. def main():
  2.     name = 'Python之禪'
  3.     with open("output.txt", "w") as f:
  4.         f.write(name)

當然,把 unicode 字符串正確地寫入文件不止一種方式,但原理是一樣的,這里不再介紹,把字符串寫入數(shù)據(jù)庫,傳輸?shù)骄W(wǎng)絡(luò)都是同樣的原理

UnicodeDecodeError

UnicodeDecodeError 發(fā)生在 str 類型的字節(jié)序列解碼成 unicode 類型的字符串時

 
 
 
 
  1. >>> a = u"禪"
  2. >>> a
  3. u'\u7985'
  4. >>> b = a.encode("utf-8")
  5. >>> b
  6. '\xe7\xa6\x85'
  7. >>> b.decode("gbk")
  8. Traceback (most recent call last):
  9.   File "", line 1, in 
  10. UnicodeDecodeError: 'gbk' codec can't decode byte 0x85 in position 2: incomplete multibyte sequence

把一個經(jīng)過 UTF-8 編碼后生成的字節(jié)序列 '\xe7\xa6\x85' 再用 GBK 解碼轉(zhuǎn)換成 unicode 字符串時,出現(xiàn) UnicodeDecodeError,因為 (對于中文字符)GBK 編碼只占用兩個字節(jié),而 UTF-8 占用3個字節(jié),用 GBK 轉(zhuǎn)換時,還多出一個字節(jié),因此它沒法解析。避免 UnicodeDecodeError 的關(guān)鍵是保持 編碼和解碼時用的編碼類型一致。

這也回答了文章開頭說的字符 "禪",保存到文件中有可能占3個字節(jié),有可能占2個字節(jié),具體處決于 encode 的時候指定的編碼格式是什么。

再舉一個 UnicodeDecodeError 的例子

 
 
 
 
  1. >>> x = u"Python"
  2. >>> y = "之禪"
  3. >>> x + y
  4. Traceback (most recent call last):
  5.   File "", line 1, in 
  6. UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
  7. >>>

str 與 unicode 字符串 執(zhí)行 + 操作時,Python 會把 str 類型的字節(jié)序列隱式地轉(zhuǎn)換成(解碼)成 和 x 一樣的 unicode 類型,但Python是使用默認的 ascii 編碼來轉(zhuǎn)換的,而 ASCII字符集中不包含有中文,所以報錯了。相當于:

 
 
 
 
  1. >>> y.decode('ascii')
  2. Traceback (most recent call last):
  3.   File "", line 1, in 
  4. UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)

正確地方式應(yīng)該是找到一種包含有中文字符的字符編碼,比如 UTF-8或者 GBK 顯示地把 y 進行解碼轉(zhuǎn)換成 unicode 類型

 
 
 
 
  1. >>> x = u"Python"
  2. >>> y = "之禪"
  3. >>> y = y.decode("utf-8")
  4. >>> x + y
  5. u'Python\u4e4b\u7985'

Python3中的字符串與字節(jié)序列

Python3對字符串和字符編碼進行了很徹底的重構(gòu),完全不兼容Python2,同時也很多想遷移到Python3的項目帶來了很大的麻煩,Python3 把系統(tǒng)默認編碼設(shè)置為 UTF-8,字符和二進制字節(jié)序列區(qū)分得更清晰,分別用 str 和 bytes 表示。文本字符全部用 str 類型表示,str 能表示 Unicode 字符集中所有字符,而二進制字節(jié)數(shù)據(jù)用一種全新的數(shù)據(jù)類型,用 bytes 來表示,盡管Python2中也有bytes類型,但那只不過是str的一個別名。

 
 
 
 
  1. >>> a = "a"
  2. >>> a
  3. 'a'
  4. >>> type(a)
  5. >>> b = "禪"
  6. >>> b
  7. '禪'
  8. >>> type(b)

bytes

Python3 中,在字符引號前加‘b’,明確表示這是一個 bytes 類型的對象,實際上它就是一組二進制字節(jié)序列組成的數(shù)據(jù),bytes 類型可以是 ASCII范圍內(nèi)的字符和其它十六進制形式的字符數(shù)據(jù),但不能用中文等非ASCII字符表示。

 
 
 
 
  1. >>> c = b'a'
  2. >>> c
  3. b'a'
  4. >>> type(c)
  5. >>> d = b'\xe7\xa6\x85'
  6. >>> d
  7. b'\xe7\xa6\x85'
  8. >>> type(d)
  9. >>>
  10. >>> e = b'禪'
  11.   File "", line 1
  12. SyntaxError: bytes can only contain ASCII literal characters.

bytes 類型提供的操作和 str 一樣,支持分片、索引、基本數(shù)值運算等操作。但是 str 與 bytes 類型的數(shù)據(jù)不能執(zhí)行 + 操作,盡管在python2中是可行的。

 
 
 
 
  1. >>> b"a"+b"c"
  2. b'ac'
  3. >>> b"a"*2
  4. b'aa'
  5. >>> b"abcdef\xd6"[1:]
  6. b'bcdef\xd6'
  7. >>> b"abcdef\xd6"[-1]
  8. 214
  9. >>> b"a" + "b"
  10. Traceback (most recent call last):
  11.   File "", line 1, in 
  12. TypeError: can't concat bytes to str

python2 與 python3 字節(jié)與字符對比

總結(jié)

  • 字符編碼本質(zhì)上是字符到字節(jié)的轉(zhuǎn)換過程
  • 字符集的演進過程是:ascii、eascii、ios8895-x,gb2312... Unicode
  • Unicode是字符集,對應(yīng)的編碼格式有UTF-8,UTF-16
  • 字節(jié)序列存儲的時候有大小端之分
  • python2中字符與字節(jié)分別用unicode和str類型表示
  • python3中字符與字節(jié)分別用str與bytes表示

網(wǎng)站標題:一籌莫展?來看看字符編碼的前世今生吧
標題URL:http://m.5511xx.com/article/dhigehd.html