python編碼注意

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

Python 2.7.12 (v2.7.12:d33e0cf91556, Jun 27 2016, 15:24:40) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.getdefaultencoding()
'ascii'


Python 3.6.2 (v3.6.2:5fd33b5, Jul  8 2017, 04:57:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.getdefaultencoding()
'utf-8'

2. 常見編碼狀況linux

print sys.getdefaultencoding()    #系統默認編碼
print sys.getfilesystemencoding() #文件系統編碼
print locale.getdefaultlocale()   #系統當前編碼
print sys.stdin.encoding          #終端輸入編碼
print sys.stdout.encoding         #終端輸出編碼

window終端輸出windows

ascii
mbcs
('zh_CN', 'cp936')
cp936
cp93

linux終端輸出bash

ascii
UTF-8
('zh_CN', 'UTF-8')
UTF-8
UTF-8

3. python str->unicode是decode,unicode->str是encode,見下圖函數

sm.ms

>>> import sys
>>> sys.getdefaultencoding()
'ascii'
>>> a='強'  # str字符串
>>> b=u'強'  # unicode字符串
>>> print isinstance(a, str)
True
>>> print isinstance(b, unicode)
True

# 由於只有unicode纔有encode方法,此處python會作默認轉換,也即a.decode('ascii').encode('utf-8')
# 會獲取默認編碼ascii轉換中文字符,固然錯誤,報UnicodeDecodeError
>>> a.encode('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc7 in position 0: ordinal not in range(128)

# 指定utf-8再轉換就會正確解析,結果unicode字符串,注意u'\u01ff'前面的u,觀察這個便可知道當前是unicode or 二進制字節碼
>>> a.decode('utf-8')
u'\u01ff'

# 不需轉換,顯示二進制字節碼
>>> str(a)
'\xc7\xbf'

# b是unicode類型,需轉化爲str類型,b.encode('ascii')報錯
>>> str(b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\u5f3a' in position 0: ordinal not in range(128)

# unicode沒有decode,需轉爲str,b.encode('ascii'),轉化時出錯
>>> b.decode('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27\lib\encodings\utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeEncodeError: 'ascii' codec can't encode character u'\u5f3a' in position 0: ordinal not in range(128)

# 指定編碼正確轉換
>>> b.encode('utf-8')
'\xe5\xbc\xba'
>>>

 

4. python進行同時包含str和unicode的運算時(+,%等),一概轉爲unicode處理,固然結果也是unicodeui

>>> a='強'  # str字符串
>>> b=u'強'  # unicode字符串
# 這裏str和unicode運算,所有轉化爲unicode,str轉unicode時用ascii轉換,固然報錯
>>> a+b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc7 in position 0: ordinal not in range(128)

# 此處都是str不用轉,正確
>>> '強%s' % a
'\xc7\xbf\xc7\xbf'

# 此處b是unicode,至關於'強%s'.decode('ascii') % b, 因此錯誤
>>> '強%s' % b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc7 in position 0: ordinal not in range(128)

# 反過來也是同樣的
>>> u'強%s' % a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc7 in position 0: ordinal not in range(128)
>>> u'強%s' % b
u'\u5f3a\u5f3a'

5. 以上都是默認ascii編碼致使的,那麼設置下python默認編碼就能夠了編碼

>>> import sys
>>> sys.setdefaultencoding('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'setdefaultencoding'
# 注意須要reload下
>>> reload(sys)
<module 'sys' (built-in)>
>>> sys.setdefaultencoding('utf-8')
>>> sys.getdefaultencoding()
'utf-8'

>>> a='強'  # str字符串
>>> b=u'強'  # unicode字符串
# 再進行以上操做,都正確了
>>> a+b
u'\u01ff\u5f3a'
>>> '強%s' % a
'\xc7\xbf\xc7\xbf'
>>> '強%s' % b
u'\u01ff\u5f3a'
>>> u'強%s' % a
u'\u5f3a\u01ff'
>>> u'強%s' % b
u'\u5f3a\u5f3a'
>>> a.encode('utf-8')
'\xc7\xbf'
>>> b.decode('utf-8')
u'\u5f3a'
>>> str(a)
'\xc7\xbf'
>>> str(b)
'\xe5\xbc\xba'

6. python文件默認編碼也是ascii,假若有中文就會報錯以下code

假若有t.py文件,裏面有非ascii字符orm

# file t.py

a='夏天'

執行時會報錯utf-8

E:/>python t.py
  File "t.py", line 1
SyntaxError: Non-ASCII character '\xcf' in file t.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

 在頭部加入,指定源代碼編碼格式

# -*- coding: utf-8 -*-
或者
#coding=utf-8

聲明下默認編碼便可

7. 如文件編碼爲ANSI的,裏面有中文的unicode定義,也會報錯

t.py

#coding=utf-8
a='夏天'
b=u'秋天'

執行也會報錯 

E:\>python t.py
  File "t.py", line 3
    b=u'秋天'
SyntaxError: (unicode error) 'utf8' codec can't decode byte 0xc7 in position 0: invalid continuation byte

把文件編碼改成UTF-8便可解決

8. print, 終端亂碼

print和終端相關,會根據sys.stdin.encoding,  sys.stdout.encoding來處理,若是輸出的字符串和終端編碼不同就會亂碼

t.py

#! -*- coding:utf-8 -*-
a='中文'
print a
print type(a)

windows下 

E:\>python t.py
涓枃
<type 'str'>

linux下

# python t.py 
中文
<type 'str'>

由於windos控制檯編碼爲cp936編碼即gbk編碼,而變量a自己編碼爲utf-8

那麼定義的unicode字符如何呢,見下面

#! -*- coding:utf-8 -*-
a='中文'
print a  # 涓枃
print type(a)  # <type 'str'>
b=a.decode('utf-8')  
print b  # 中文

b=u'中文'
print b  # 中文
print type(b)  # <type 'unicode'>
print b.encode('gbk')  # 中文

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

可見,unicode的字符print正常,按gbk encode->str時也正常,爲何呢

可這樣簡單理解,print輸出到終端時,要是str,若是str的編碼與終端編碼不一致,那麼亂碼

若是不是str,則須要轉爲str,這個是獲取終端編碼,也即python替你作了, encode('gbk')

但str(b)咋又報錯了呢,這是由於,str是python內建函數,會獲取getdefaultencoding,而這個編碼是ascii,因此報錯

再進一步,加入重定向到文件呢

#! -*- coding:utf-8 -*-
b=u'中文'
print b

python t.py > result 

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

由於輸出到控制檯時,print 使用的是控制檯的默認編碼,而重定向到文件時,print 就不知道使用什麼編碼了,因而就使用了默認編碼 ascii 致使出現編碼錯誤。這時咱們就不該該讓python幫咱們作,咱們本身指定

#! -*- coding:utf-8 -*-
b=u'中文'
print b.encode('utf-8')

這樣就會正常

9. write

#! -*- coding:utf-8 -*-
with open('ttt.txt', 'w') as f:
  f.write('test') # 正常寫入
  f.write('夏天') # 正常寫入
  #f.write(u'秋天') # 錯誤,因爲是unicode,python要轉換爲str再寫入,encode時用的ascii,觸發UnicodeEncodeError異常
  f.write(u'秋天'.encode('utf-8')) # 寫入正常,unicode->str

或者指定默認編碼,這樣就不用手動encode了,見下

#! -*- coding:utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
with open('ttt.txt', 'w') as f:
  f.write('test,') # 正常寫入
  f.write('夏天,') # 正常寫入
  f.write(u'秋天,') # 寫入正常

10. read

#! -*- coding:utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
with open('ttt.txt', 'w') as f:
  f.write('test,') # 正常寫入
  f.write('夏天,') # 正常寫入,亂碼
  f.write(u'秋天,') # 寫入錯誤,因爲是unicode,python要轉換爲str再寫入,encode時用的ascii,觸發UnicodeEncodeError異常
  #f.write(u'秋天'.encode('utf-8')) # 寫入正常,unicode->str

with open('ttt.txt') as f:
  for line in f:
    print line, type(line)  # test澶忓ぉ縐嬪ぉ <type 'str'>
    line2 = line.decode('utf-8')
    print line2, type(line2) # test夏天秋天 <type 'str'>

print '-----------------------------'

# 經過io包下的open打開文件可設置編碼
from io import open
with open('ttt.txt', encoding='utf-8') as f:
  for line in f:
    print line, type(line) # test夏天秋天 <type 'unicode'>

# 由上可見,內建函數open,不能指定編碼,其按客戶端所在編碼解碼,line類型是str
# io.open可指定編碼,同時line讀取類型爲unicode

建議措施:

以上全部其實就是在不一樣地方python默認轉換時採用的編碼和咱們設置的編碼不一致致使的,因此分析時先分析當前python應該獲取什麼編碼,而後再分析。好比,str(..) 會獲取getdefaultencoding,print會獲取sys.stdout.encoding等

1. 牽扯到中文的地方,都聲明頭部編碼,同時文件編碼設爲utf-8

# -*- coding: utf-8 -*-
或者
#coding=utf-8

2. 同時設置sys 默認編碼

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

3. python代碼內部請所有使用unicode編碼,在獲取外部內容時,先decode爲unicode,向外輸出時再encode爲str

4. 在定義變量或者正則時,也定義unicode字符,如a=u」中文」;res=r」」+u」正則」。

相關文章
相關標籤/搜索