在學習python以及在使用python進行項目開發的過程中,經常會使用print語句打印一些調試信息,這些調試信息中往往會包含中文,如果你使用python版本是python2.7,或許你也會遇到和我一樣的問題:那就是print打印中文異常以及顯示亂碼問題。本文主要分析一下在linux下使用python2.7的print語句中文異常以及終端顯示中文亂碼問題的原因及解決辦法。轉載請注明出處,謝謝!
1.print打印顯示的過程
![]()
圖1. Print打印顯示過程
Python2.7中調用print打印var 變量時,操作系統會對var做一定的字符處理:如果var是str類型的變量,則直接將var變量交付給終端進行顯示;如果var變量是unicode類型,則操作系統首先將var編碼成str類型的對象(編碼格式取決於stdout的編碼格式),然后再交由終端進行顯示。在終端顯示時,如果str類型的變量的編碼方式和終端設置的編碼方式不一致,很可能會出現亂碼問題。
2.print中文字符出現錯誤問題
在python源碼中print中文字符,時常會出現Non-ASCII character和UnicodeEncodeError兩類錯誤。下面分別一一介紹。
2.1 Non-ASCII character錯誤
print.py源碼示例(代碼1):
import sys
print sys.getdefaultencoding()
a="測試"
b=u"測試"
print a
print b
這段代碼試圖在linux的終端打印變量a和b的值,但是在實際執行的過程中,會提示Non-ASCII character錯誤:

原因:該print.py的文件格式是utf-8(可以vi print.py,然后在命令模式下,輸入:set fileencoding,查看文件的編碼方式,)。“測試”對應的utf-8編碼為:'\xe6\xb5\x8b\xe8\xaf\x95',由於print.py中含有中文,且print.py沒有指定編碼方式,python會按照系統的默認編碼解析執行print.py(這里的系統默認編碼是ascii,查看系統的默認編碼,可以調用sys.getdefaultencoing()函數),因此會提示Non-ASCII character的錯誤。
解決辦法:在print.py起始處,指定編碼方式為utf-8,這樣python在執行代碼時,就知道要按照utf-8來解釋執行代碼了。代碼2:
#coding=utf-8
import sys
print sys.getdefaultencoding()
a="測試"
b=u"測試"
print a
print b
運行結果如下:

2.2 UnicodeEncodeError問題
代碼2在192.168.86.61上能正常運行,但是換到另一台機器192.168.86.157就不能正常運行了,現象如下:

從打印信息來看,print a可以正常輸出,而print b就會出現UnicodeEncodeError錯誤,這是為什么呢??
根據第1節中的介紹,變量b是unicode類型的,操作系統會按照stdout的默認編碼將b編碼成str類型的變量,根據報錯信息猜測系統stdout的默認編碼是ascii,而ascii字符的范圍是0-127,因此會報上述錯誤。而變量a是str類型,調用print時,不需要經過操作系統進行編碼,所以能正常輸出。
那么,如何驗證157上的系統stdout的編碼方式是不是ascii呢?可以通過sys.stdout.encoding查看stdout的編碼方式,這里的輸出結果是ANSI_X3.4-1968,其別名就是ASCII,哈哈,原來真的是這樣。
那么,為什么在192.168.86.61上,print b就能正常被打印輸出呢?想要知道原因,讓我們查看一下192.168.86.61上的stdout的編碼方式,通過sys.stdout.encoding查得stdout的編碼方式為utf-8,unicode類型的變量b的print時,首先被編碼成utf-8,然后在送至終端顯示,一切正常!
至此,你可能明白了該問題產生的原因,那么,這個問題該怎么解決呢?一般建議在調用print打印變量時,首先調用encode()函數將unicode類型的變量進行編碼,轉換成str類型的變量,代碼3如下:
#coding=utf-8
import sys
print sys.getdefaultencoding()
a="測試"
b=u"測試"
print a
print b.encode('utf-8')
之后,程序可以正常運行,如下:

3.linux終端顯示中文亂碼
第1節中曾提到過:如果str類型的變量的編碼方式和終端設置的編碼方式不一致,在終端顯示時就會出現中文亂碼問題。筆者使用的終端的編碼方式為utf-8,如下圖:

如果將終端的編碼方式改為GB2312,則中文就會出現亂碼。因為b.encode('utf-8')的編碼為utf-8,而終端的為GB2312,因此導致了亂碼。

解決方法就是要保持終端編碼和待顯示的變量的編碼方式的一致。
