亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.430618.com 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

一、字符編碼初探

字符編碼其實就是將人類能識別的字符與計算機能識別的數字對應起來。ASCII(American Standard Code for Information Interchange)美國信息交換標準代碼,是最早最通用的單字節編碼標準。

ASCII單字節編碼表示范圍有限,是不能滿足表示中文的,于是基于ASCII擴展,制定了GB2312標準(GB是國標的意思)。現在最常用的中文編碼標準GBK又是GB2312的升級,能表示更多的字符。

計算機的發展和普及在各個國家和地區各有不同,各國也是制定了自己的編碼標準,這些基于ASCII擴展而來,使用多字節表示字符的延伸編碼方式稱為 ANSI 編碼。在簡體中文windows系統中,ANSI編碼代表GBK,而韓文系統中ANSI編碼代表EUC-KR。

由于不同國家和地區編碼標準不一致,也導致了它們之間存在復雜的編碼轉換,于是誕生了unicode編碼方式,以提供統一的編碼標準,所以unicode也叫萬國碼,其標準稱呼應該是Universal Multiple-Octet Coded Character Set,簡稱UCS。而unicode又存在多種編碼方式的實現,其中UTF-8是最常用的一種UTF(UCS Transfer Format)標準。

二、Python2/python3的默認編碼

python2的默認編碼是ascii,python3則是utf-8。可以通過如下方式獲取:

python2 -c "import sys;print(sys.getdefaultencoding())"
python3 -c "import sys;print(sys.getdefaultencoding())"

可以在python文件開頭設置默認編碼,python3默認就使用了utf-8,所以不需要該編碼聲明。

# -*- coding: UTF-8 -*-
# coding=utf-8

python2雖然指定了編碼,但還是不能很好地處理中文,在終端輸出、文件讀寫、json處理等都難免遇到問題。要解決各種編碼問題,需要明確當前編碼是什么,python編碼的相關特性,數據來源是什么編碼,數據輸出又是什么編碼。

三、起點-python2打印輸出中文

我們在python2文件開頭設置了編碼方式為utf-8,如果cmd終端字符編碼不是utf-8,要正常打印輸出中文,還 需要將字符串先解碼,再編碼成終端的編碼格式輸出 

比如,中文windows系統的cmd終端默認是gbk中文編碼,chcp查看活動代碼頁編號是936,也就是gbk編碼,要正常輸出中文,字符串需要先解碼,再編碼成終端的gbk格式打印,如下。

# -*- coding: UTF-8 -*-
#python2
import sys
print("中文".decode('utf-8').encode(sys.stdout.encoding))  #文件開頭已經指定默認編碼為utf-8,但是終端是gbk,所以需要先decode('utf-8') 再 encode(sys.stdout.encoding)

四、特性初識-python2/python3的unicode類型

python2與python3在定義unicode類型時是通用的。

#定義unicode類型
u = u'中文'
u = u"中文"
u = u'''中文'''
u = u"""中文"""

我們知道unicode是通用的,所以無論使用python2還是python3執行如下代碼時均不會出現亂碼。

print(u"中文")
print(u'\u4e2d\u6587')#均輸出中文

所以前面python2 打印輸出 的問題其實可以簡寫。

print("中文".decode('utf-8'))   #"中文".decode('utf-8')是unicode類?

五、區別-python2/python3的str、bytes類型

python2與python3在定義str、bytes類型時是通用的。

#定義str類型
s = 'test'
s = "test"
s = '''test'''
s = """test"""
?
#定義bytes類型
b = b'test'
b = b"test"
b = b'''test'''
b = b"""test"""

首先, bytes類型是字節序列,一個事實上的bytes類型每個元素就是一個字節 。

打開一個gbk編碼的文本,可以看到其對應十六進制字符碼。

理解Python的編碼問題

 

utf-8編碼的文本,字符碼則不同。可以看到, 能表示更多字符的編碼標準,需要更多的字節來表示字符 

理解Python的編碼問題

 

首先查看如下python2代碼運行情況。

理解Python的編碼問題

 

可以看到,python2處理str和bytes時是混用的,可以進行+運算,但它們都是字節序列。 python2沒有將str和bytes型數據做明顯的區分,是一種隱式的混用,并且python2處理str類型時優先將其視為bytes 。事實上str.decode是bytes.decode,從而轉換成unicode。 str/bytes/unicode三者關系:str(bytes)—decode—>unicode—encode—>str(bytes) 。

不同于python2, python3對str和bytes型數據作了明顯區分,str表示文本,默認就是原生unicode的utf-8編碼格式,bytes型數據就表示二進制數據 ,用下標取bytes類型的單個元素返回的是int類型,而在python2中用下標取bytes類型的單個元素返回的還是bytes。 bytes/str/unicode三者關系:bytes—decode—>str(unicode)—encode—>bytes ,不能像python2那樣string.decode。

s = '中文'
b = bytes(s,encoding='utf-8') # s.encode('utf-8')
s = str(b,encoding='utf-8') # b.decode('utf-8')

上面python2的實驗,標準輸出編碼是gbk,將\xd6\xd0\xce\xc4復制到python3驗證編碼區別,如下python3的運行情況,可以看到gbk可以正常解碼,再進行encode(‘utf-8′)得到bytes字節序列是不是與前面utf-8文本中”中文”的十六進制數據相同。

理解Python的編碼問題

 

六、文件路徑/文件名/文件讀寫

1.文件路徑的困惑

存在如下一段代碼,遍歷目錄里面的文件。

# -*- coding: UTF-8 -*-

import os

all_files = []
for filepath, dirnames, filenames in os.walk(directory):
	for filename in filenames:
		tmppath = os.path.join(filepath, filename)
		all_files.Append(tmppath)
print(all_files)

python2/python3結果對比。python3將str視為unicode處理的,所以正常顯示。可以看到python2是以gbk編碼來識別目錄的。

理解Python的編碼問題

 

當前活動代碼頁是gbk,那python2識別目錄是否會受到當前cmd終端編碼方式影響?改變當前活動代碼頁為utf-8后,目錄還是以gbk編碼識別,encode成utf-8才能正常打印出目錄名。

理解Python的編碼問題

 

文章開頭了解到ANSI編碼的特點,是否可以推測python2是以當前系統ANSI編碼獲取目錄名的呢?linux shell驗證確實如此。

理解Python的編碼問題

 

2.python2的文件名亂碼

python2運行如下代碼,文件名出現了亂碼。

# -*- coding: UTF-8 -*-
# python2/python3

with open('中文2.txt','w+') as f:
	f.write("中文")?
理解Python的編碼問題

 

前面推測python2是以當前系統ANSI編碼獲取目錄名,所以創建文件是否也是這樣,由于聲明了編碼方式是utf-8,而文件名”中文2.txt”字符串是以bytes、utf-8格式存儲的,與gbk不一致,所以導致亂碼。嘗試將代碼改成如下,文件名正常。

# -*- coding: UTF-8 -*-
# python2

with open('中文2.txt'.decode('utf-8').encode('gbk'),'w+') as f:  #當前編碼是utf-8 所以先decode,再encode為系統的gbk編碼
	f.write("中文")
理解Python的編碼問題

 

那么找文件讀又會是怎樣?

# -*- coding: UTF-8 -*-
# python2

with open('中文2.txt','r') as f:
	print(f.read().decode('utf-8'))

python2執行報錯No such file or directory,沒有文件或目錄。

理解Python的編碼問題

 

修改文件名為 ‘中文2.txt’.decode(‘utf-8′).encode(‘gbk’) 后才正常找到了文件,由此可見, python2在識別目錄、open創建、讀取文件時均以系統ANSI編碼識別的 ,處理中文名稱時, 需要將目錄/文件名字符串先解碼,再編碼成系統的ANSI編碼格式 。

3.寫入是否正常

打開前面python2生成的兩個文件,都是utf-8格式,內容中文顯示正常!體會到python2的詭異編碼了嗎?至于這一點,忘了吧…

python3就沒那么奇葩了,寫入文本后,中文windows系統是ANSI編碼,而linux是utf-8編碼。

理解Python的編碼問題

 


理解Python的編碼問題

 

python3 open文件操作若不指定編碼,則默認以系統ANSI編碼寫入、讀取文本。 建議如果不是以二進制讀取和寫入,open文件時可指定文本的編碼方式。

f = open("中文1.txt",'a+',encoding='utf-8')

4.讀取小結

不管python2還是python3,解決編碼問題的核心都是要解決編碼統一。通過”python2/python3的默認編碼”小節,我們認識到python2與python3默認編碼的區別,實際上 python文件開頭的編碼聲明聲明的是當前腳本內字符串的編碼 ,所以才有了python2打印輸出中文時需要先decode(‘utf-8′),再encode(‘gbk’)為cmd終端編碼格式,以及中文文件名的編碼轉換,至于python3,統一了編碼,str就是原生unicode,具有普適性,就沒有那么多編碼轉換。總之,讀取文件時,需要明確文件的編碼,當前python腳本文件的編碼聲明,輸出的編碼。如果一個utf-8格式文本文件內包含”\xd6\xd0\xce\xc4″、”\u4e2d\u6587″等字符串,讀取后又如何處理呢?

理解Python的編碼問題

 

python2 可以以string-escape和unicode-escape方式解碼。

# -*- coding: UTF-8 -*-
# python2

with open('a.txt','r') as f:
	lines = f.readlines()
	print(lines)  #讀取后會加上轉義 ['\xd6\xd0\xce\xc4rn', '\u4e2d\u6587']
	for line in lines:
		if '\x' in line:
			print(line.decode('string-escape'))
		if '\u' in line:
			print(line.decode('unicode-escape'))

python3 可以參考如下方式處理。

# -*- coding: UTF-8 -*-

import codecs

with open('a.txt','r',encoding='utf-8') as f:
	lines = f.readlines()
	print(lines)
	for line in lines:
		if '\x' in  line:
			bline = bytes(bytearray.fromhex(line.strip().replace('\x','')))
			print(bline.decode('gbk'))   #\xd6\xd0\xce\xc4 是"中文"gbk格式的字符碼
		if '\u' in line:
			print(codecs.decode(line,'unicode_escape'))

七、python2 json的問題

存在如下代碼。

# -*- coding: UTF-8 -*-
# python2

import json

a = {'a':'test','語言':'中文'}
with open('a.txt','a+') as f:
	f.write(json.dumps(a))

運行之后,json.dumps會將中文以unicode的字符碼形式dump,并不是真正的中文,需要指定ensure_ascii=False參數來dump真正的中文。

json.dumps(a,ensure_ascii=False)

如下,dumps后文件為utf-8格式,如果讀取進行json.loads,得到的字典”鍵”和”值”就都會是unicode類型的。

理解Python的編碼問題

 

# -*- coding: UTF-8 -*-

import json

with open('a.txt','r+') as f:
	print(json.loads(f.read()))

結果如下。

理解Python的編碼問題

 

需要對獲取到的字典”鍵”和”值”進行解碼的話,這里可以參考一段代碼處理。

def unicode_convert(input):
	if isinstance(input, dict):
		return {unicode_convert(key): unicode_convert(value) for key, value in input.items()}
	elif isinstance(input, unicode):
		return input.encode('utf-8')
	else:
		return input

八、總結

4月20日,Python2的最后一個版本發布:2.7.18。可以說python2已是過去式,python3才是未來。可為什么文章大部分內容卻還是python2的呢?一是確實python2的字符編碼問題多,解決這些問題能更好的理解python編碼機制;二是即便python2不再有,但編碼問題一定一直會存在,不管是python自己生成處理的數據還是其它源數據。從解決python2的編碼問題到了解python2與python3的差異,總結出以下解決編碼問題的關鍵點,如有不當,還望指正。

1.python2的默認編碼是ascii,python3則是utf-8。

2.python文件開頭的編碼聲明聲明的是當前腳本內字符串的編碼,要避免編碼錯誤,需要統一數據源,聲明的編碼類型,數據輸出三者的編碼。

3.python2沒有將str和bytes型數據做明顯的區分,是一種隱式的混用,并且python2處理str類型時優先將其視為bytes。str/bytes/unicode三者關系:str(bytes)—decode—>unicode—encode—>str(bytes)。

4.python3對str和bytes型數據作了明顯區分,str表示文本,默認就是原生unicode的utf-8編碼格式,bytes型數據就表示二進制數據。bytes/str/unicode三者關系:bytes—decode—>str(unicode)—encode—>bytes。

5.python2在識別目錄、open創建、讀取文件時均以系統ANSI編碼識別的。

6.python3 open文件操作若不指定編碼,則默認以系統ANSI編碼寫入、讀取文本。

分享到:
標簽:編碼 Python
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定