溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

python編碼的原理及使用

發(fā)布時(shí)間:2021-06-24 14:16:14 來(lái)源:億速云 閱讀:204 作者:chen 欄目:大數(shù)據(jù)

本篇內(nèi)容主要講解“python編碼的原理及使用”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“python編碼的原理及使用”吧!

python編碼深度解析

一、字符、字節(jié)、編碼

1.1 為什么編碼?

編碼就是為了解決字符和字節(jié)之間的關(guān)系。

python編碼的原理及使用

1.2 為什么要分字符和字節(jié)?

分字符和字節(jié)是為了解決人機(jī)之間的關(guān)系,一般人只能讀字符,機(jī)器只能識(shí)別字節(jié)。

1.3 字符和編碼之間的關(guān)系?

字符'a',人能夠識(shí)別,機(jī)器不能識(shí)別,機(jī)器只能識(shí)別字節(jié)。

所以需要一種把字符'a'轉(zhuǎn)換為字節(jié)的技術(shù)。

這種技術(shù)就是編碼,例如我們最常見(jiàn)的ASCII(American Standard Code for Information Interchange)碼,就包含英文字符數(shù)字和一些控制字符。

我們通過(guò)ASCII碼表就可以找到字符'a'對(duì)應(yīng)的數(shù)字為97,這樣我們就可以把字符'a'通過(guò)編碼轉(zhuǎn)換為二進(jìn)制字節(jié)01100001,這樣機(jī)器就能識(shí)別了。

我們一般說(shuō)的編碼,指字符集和字符集中字符對(duì)應(yīng)的值,而不是編碼方式

一般的編碼方式就是字符集中字符的編碼對(duì)應(yīng)的二進(jìn)制

Unicode字符集有所不同,有多種常用的編碼方式,后面詳細(xì)介紹。

1.4 為什么有不同的編碼

因?yàn)橛胁煌娜?,使用了不同的字符,如中?guó)人使用了中文字符,正如你現(xiàn)在讀到的字符一樣,我們?cè)贏SCII碼表中是找不到對(duì)應(yīng)字符的,自然也不能根據(jù)ASCII把字符轉(zhuǎn)換為字節(jié)。

所以我們自己就需要新的編碼方式,來(lái)包含我們自己的字符,從最開(kāi)始的GB2312到GBK,再到GB18030。

同理,其他語(yǔ)言也有自己對(duì)應(yīng)的字符集和編碼。

二、Unicode

在國(guó)際化的進(jìn)程中,只玩自己的編碼肯定是不行的,所以需要統(tǒng)一的編碼,就是包含世界字符,這樣只需要在應(yīng)用中使用Unicode碼,就能避免為應(yīng)用做適配。

我們知道編碼是包含字符集和字符集中字符對(duì)應(yīng)的值,一般字符集和對(duì)應(yīng)的值放在一起做為一個(gè)對(duì)應(yīng)編碼的碼表。

Unicode有2個(gè)字符集,UCS-2和UCS-4,因?yàn)閁CS-4兼容UCS-2,所以這里介紹一下UCS-4。

UCS-4使用4字節(jié)編碼,最高位都是0,所以最高字節(jié)的8位有7位有效位。

UCS-4使用最高字節(jié)的7位來(lái)標(biāo)識(shí)組(group),也就是有2^7=128個(gè)組。

UCS-4使用次高字節(jié)來(lái)標(biāo)識(shí)平面(plane),8位共2^8=256個(gè)平面。

UCS-4使用第3字節(jié)來(lái)標(biāo)識(shí)行(row),8位2^8=256行。

UCS-4使用第4字節(jié)來(lái)標(biāo)識(shí)碼位(cell),同理有256個(gè)碼位。

group 0的plane 0被稱作Basic Multilingual Plane(BMP)

UCS-4中,高兩個(gè)字節(jié)為0的碼位被稱作BMP,BMP去掉2個(gè)全為0的高字節(jié)之后,就是2字節(jié)的UCS-2。

通過(guò)上面的介紹我們很容易算出:UCS-2共有2^16=65536個(gè)碼位。

這也是在python2.x中:

import sys
print sys.maxunicode

打印的值是65535的原因(從0開(kāi)始,所以最大碼位是65535)。

python編碼的原理及使用

Unicode計(jì)劃使用了17個(gè)平面,每個(gè)平面65536個(gè)碼位,共有17×65536=1114112個(gè)碼位。

這也是在python3.x中:

import sys
print sys.maxunicode

打印的值是1114111的原因

python編碼的原理及使用

三、python亂碼的起源

先介紹一下'中文'這2個(gè)字符的相關(guān)編碼:

'中文'的Unicode編碼:\u4e2d\u6587 '中文'的UTF-8編碼:\xe4\xb8\xad\xe6\x96\x87 '中文'的GBK編碼:\xd6\xd0\xce\xc4

下面代碼不是通過(guò)交互程序,而是寫入文件,在cmd執(zhí)行。

print("中文")

加入有文件名為test-encoding.py的文件內(nèi)容如上所示,我們?cè)谥形沫h(huán)境windows下執(zhí)行該文件,就會(huì)得到下面的錯(cuò)誤。

python編碼的原理及使用

python編碼的原理及使用

我們可以通過(guò)查看test-encoding.py文件的16進(jìn)制,可以看出test-encoding.py文件使用的是UTF-8編碼,對(duì)比'中文'的編碼得出。

我們也可以看出這不是一個(gè)執(zhí)行時(shí)候的錯(cuò)誤,因?yàn)檫@是一個(gè)SyntaxError,說(shuō)明是一個(gè)語(yǔ)法錯(cuò)誤。

同時(shí)這個(gè)錯(cuò)誤也告訴了我們?cè)?,是因?yàn)橛蟹茿SCII字符,因?yàn)閜ython默認(rèn)的編碼是ASCII,所以不能包含有非ASCII字符。

需要包含非ASCII字符我們需要一點(diǎn)特殊的處理,就是告訴python解釋器,文件使用的編碼方式。

# -*- coding: utf-8 -*-
print("中文")

添加的注釋部分是告訴python解釋器使用utf-8方式做為字符與字節(jié)之間的編碼方式。

告訴解釋器使用utf-8編碼就夠了嗎?

顯然不是,因?yàn)檫€涉及到其他的編碼方式,例如我們?cè)赾md中執(zhí)行上面的文件,會(huì)得到輸出

涓枃

python編碼的原理及使用

上面的輸出值其實(shí)就是'中文'這2個(gè)字符的UTF-8編碼\xe4\xb8\xad\xe6\x96\x87對(duì)應(yīng)的GBK編碼。 可以自己對(duì)照GBK碼表檢查,也可以使用在線轉(zhuǎn)換編碼工具轉(zhuǎn)換驗(yàn)證。

因?yàn)閣indows默認(rèn)的代碼頁(yè)是936,也就是GBK編碼。

python編碼的原理及使用

可以通過(guò)下面的2中方式解決:

# -*- coding: utf-8 -*-
print(u"中文")
print(a.decode('utf-8').encode('gbk'))

四、令人困惑的默認(rèn)編碼

python2.x默認(rèn)的編碼是ASCII python3.x默認(rèn)的編碼是UTF-8

可以通過(guò)sys.getdefaultencoding()查看默認(rèn)編碼方式

那么默認(rèn)的編碼方式到底是什么?

在有些風(fēng)騷的操作中,可能會(huì)教你使用下面的方式解決亂碼:

# -*- coding: utf-8 -*-
import sys

print(sys.getdefaultencoding())

reload(sys)
sys.setdefaultencoding('utf-8')

print(sys.getdefaultencoding())

a = '中文'
print(a)

然而這并沒(méi)有什么用,因?yàn)檫@是輸出端的問(wèn)題

那這個(gè)騷操作在什么地方有用呢?

答案是處理unicode的時(shí)候:

# -*- coding: utf-8 -*-
import sys

print(sys.getdefaultencoding())

# reload(sys)
# sys.setdefaultencoding('utf-8')

with open(r'F:\tmp\test.txt', 'w') as f:
  f.write('測(cè)試')
  f.write(u'測(cè)試')

執(zhí)行上面的代碼,會(huì)得到下面的錯(cuò)誤(2.x):

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

python編碼的原理及使用

但是把注釋代碼取消注釋,就沒(méi)有問(wèn)題了。

我們來(lái)分析一下: f.write(str)接收的是一個(gè)str類型的參數(shù),u'測(cè)試'是一個(gè)unicode類型。

unicode到str需要encode,字節(jié)和字符之間的轉(zhuǎn)換是需要編碼的,顯然這里使用的是:

u'測(cè)試'.encode(sys.getdefaultencoding())

五、python 交互式編碼

python 交互式使用的編碼默認(rèn)會(huì)讀取系統(tǒng)的編碼,中文環(huán)境下windows下一般是GBK。

所以我們使用交互式的方式一般是沒(méi)有亂碼的問(wèn)題。

六、python處理網(wǎng)頁(yè)文件編碼

UnicodeEncodeError: 'gbk' codec can't encode character u'\xa0' in position 392477: illegal multibyte sequence

python編碼的原理及使用

有時(shí)候會(huì)遇到上面的錯(cuò)誤,出現(xiàn)這個(gè)錯(cuò)誤的原因基本都是因?yàn)橛休敵龅絚md的命令,也就是基本是因?yàn)閜rint('xxx')造成的,其中xxx是GBK不兼容的字符。

其實(shí)我們可以很容易的構(gòu)造一個(gè)類似的錯(cuò)誤出來(lái)(2.x):

print('?'.decode("utf-8"))
#print('?'.decode("utf-8").encode("gbk"))

在中文環(huán)境下的windows命令行執(zhí)行包含上面代碼的文件就會(huì)看到UnicodeEncodeError錯(cuò)誤。

Unicode編碼中: 基本漢字范圍:4E00-9FA5(20902個(gè)) 基本漢字補(bǔ)充:9FA6-9FEF(74個(gè)) ?的Unicode碼是:9FA6,GBK中是沒(méi)有包含?這個(gè)字的

解決辦法: 出現(xiàn)這個(gè)錯(cuò)誤,就說(shuō)明包含有超出GBK范圍的字符了,所以就不要使用GBK編碼方式了。

中文windows命令行默認(rèn)GBK,不修改代碼頁(yè)肯定有這個(gè)問(wèn)題,只有修改代碼頁(yè)才能解決。

換種思路直接輸出到文件,使用UTF-8編碼不是挺好的。

七、總結(jié)

python 2.x

python編碼的原理及使用

#a是字符串(str)類型
a = '中文'
#b是unicode類型
b = u'中文'

2者的不同之處在于:

  1. str類型使用的是系統(tǒng)默認(rèn)編碼(可設(shè)置)

  2. unicode的類型使用的是unicode的編碼

轉(zhuǎn)換: str通過(guò)decode可以獲取到unicode類型 unicode的通過(guò)encode得到str類型

2.x默認(rèn)使用的是ASCII做字符與字節(jié)之間的編碼轉(zhuǎn)換,使用的字符集是UCS-2。

因?yàn)?.x沒(méi)有byte類型,所以不同編碼之間要轉(zhuǎn)換先存儲(chǔ)為unicode編碼,然后需要什么編碼,再?gòu)膗nicode編碼轉(zhuǎn)換為對(duì)應(yīng)的編碼。

python 3.x

python編碼的原理及使用

相比于2.x,3.x版本就正常多了,和其他語(yǔ)言的邏輯保持了一致性。

首先最重要的是添加了byte類型,即字節(jié)類型。

不再顯示的使用unicode編碼,而是遵從:

字符<--->編碼<--->字節(jié)
#字符--->編碼--->字節(jié)
bs = "中文".encode('utf-8')

#字節(jié)--->編碼--->字符
ch = bs.decode("utf-8")

3.x默認(rèn)使用utf-8做字節(jié)和字符之間轉(zhuǎn)換的編碼方式,使用的字符集是UCS-4。

八、解決亂碼終極方案

亂碼說(shuō)明字節(jié)-->字符的編碼出問(wèn)題了。

所以首先得弄清楚文件、網(wǎng)絡(luò)中的字節(jié)使用的是什么編碼方式,是ASCII、GBK、UTF-8……

然后得弄清楚輸出字符的終端、編輯器是什么編碼,然后對(duì)應(yīng)起來(lái): decode、encode配對(duì)使用一樣的編碼就可以了。

有些朋友可能會(huì)說(shuō),這不是廢話嗎?我知道是什么編碼,還會(huì)亂碼?

問(wèn)題的重點(diǎn)在于:字節(jié)從哪里來(lái),顯示字符的編輯器或終端使用什么編碼。這樣至少可以定位大多數(shù)問(wèn)題。

至于中間經(jīng)過(guò)多次轉(zhuǎn)換的,那就需要仔細(xì)排查了。

到此,相信大家對(duì)“python編碼的原理及使用”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI