此文以Python 2.7为基础。(文中结果是正确的,懒得去翻源码理解有错的地方,请自行纠正,^_^!)
处理Python中文需要注意的问题: - 1.请在Python内部使用统一的编码,建议Unicode(如果你要兼容不同的I/O编码)或者(统一『UTF-8』这样不用来回转换); - 2.I/O端的编码(包括控制台及文件内容);为了保持数据的可移植性,在文件内容上请使用一致的UTF-8格式; - 3.文件系统目录编码与I/O编码有可能不一致;
unicode和str
在Python中有两种对象,unicode和str,Python内部使用两个字节表示unicode;
>>> s = "我是str" >>> type(s) <type 'str'> >>> print s 我是str >>> u = u"我是unicode" >>> type(u) <type 'unicode'> >>> print u 我是unicode
repr() 可用这个查看字节码
>>> s = "我是str" >>> s = "我是str" >>> print repr(s) '\xce\xd2\xca\xc7str' >>> s '\xce\xd2\xca\xc7str' >>> print s.__repr__() '\xce\xd2\xca\xc7str'
decode()/encode()
Python有两个函数decode(),用于将指定的编码转换成Unicode;encode()将Unicode转换成指定编码,要实现编码的转换可以通过如下方式:
# 假定a中目前是UTF8的编码格式,想转换成gb2312 a.decode('utf8').encode('gb2312')
非unicode->unicode->非unicode
有个defaultencoding
使用sys.getdefaultcoding()
查看,很多问题都是这个家伙引起的,对它要有足够的认识,它默认是ascii
>>> import sys >>> sys.getdefaultencoding() 'ascii'
控制台输入
如果是windows,这里默认将是CP936格式编码,可以通过设置命令行窗口的编码格式来改变,在窗口图标上点击右键,选择“默认值”,在打开的界面中设置“默认代码页”即可;
>>> s = raw_input() 我是控制台输入的 >>> s '\xce\xd2\xca\xc7\xbf\xd8\xd6\xc6\xcc\xa8\xca\xe4\xc8\xeb\xb5\xc4' >>> print type(s), s <type 'str'> 我是控制台输入的
源文件编码
py文件的编码定义,在py文件首行, # coding=utf-8,可以告诉编辑器及python解释器,当前py文件的编码格式
# coding=utf-8 file_name = u"中文试验.txt" # 这里表示为Unicode,输出时会转换成I/O的编码
文件中定义字符串,u表示用Unicode在内存中保存此字符串;
参考资料:Defining Python Source Code Encodings https://www.python.org/dev/peps/pep-0263/
系统和输入输出(I/O)编码
# encoding=utf-8 import os import sys import locale file_name = u"中文试验.txt" # 这里表示为Unicode,输出时会转换成I/O的编码 encoding = None ''' 操作系统中的环境变量PYTHONIOENCODING,用于说明stdin/stdout/stderr的编码格式, 此变量会被设置在sys.stdout.encoding,在py中可以直接访问。 如果未设置PYTHONIOENCODING会自动使用操作系统的编码, 如:中文Windows 10中是cp936; Linux会受环境变量$LANG的影响,如果:LANG=en_US.UTF-8,那么这里就是UTF-8 如果sys.stdout.encoding的值找不到,则系统将使用sys.getdefaultencoding()所获取的值,一般是ascii; ''' def set_encoding(): print "PYTHONIOENCODING=%s" % (os.environ.get("PYTHONIOENCODING")) print "sys.stdout.encoding=%s" % (sys.stdout.encoding) print "sys.getdefaultencoding()=%s" % (sys.getdefaultencoding()) print "locale.getdefaultlocale()[1]=%s" % (locale.getdefaultlocale()[1]) # 操作系统encoding print "locale.getpreferredencoding()=%s" % (locale.getpreferredencoding()) # 操作系统encoding global encoding if sys.stderr.encoding: encoding = sys.stderr.encoding else: encoding = sys.getdefaultencoding() def input_data(): # 将unicode转换为I/O支持的编码进行提示语的显示,读入到内存的为I/O的编码格式 s = raw_input(u"请输入你的中文名字:".encode(encoding)) fo = open(file_name, "wb+") fo.write(s) # 从I/O读入的编码格式不进行处理直接写入文件 # 所以在中文Windows 10中默认是cp936 fo.close() def load_data(): fo = open(file_name, "rb") s = fo.read() # 读入到内存后是I/O编码的格式 fo.close() d = {"Chinese": s} # 注意:前半段是Unicode,输出时会自动转换;后半段是I/O编码,不用转换 print u"Chinese:", (d["Chinese"]) set_encoding() input_data() load_data()
文件系统目录编码
文件目录操作必须知道当前系统使用的文件编码,可由sys.getfilesystemencoding()获取默认设置;在Windows 10中文版中是mbcs
,在Linux中与LANG环境变量有关,有可能UTF-8
,如果未设置LANG,将默认为US-ASCII
;
# encoding=utf-8 import sys import os encoding = None def guess_encoding(): global encoding if sys.stderr.encoding: encoding = sys.stderr.encoding else: encoding = sys.getdefaultencoding() print "sys.stderr.encoding=%s" % (sys.stderr.encoding) print "sys.getdefaultencoding()=%s" % (sys.getdefaultencoding()) print "sys.getfilesystemencoding()=%s" % (sys.getfilesystemencoding()) def ls(): dir = u"C:\\Users\\jilili\\Documents\\地形图\\" # 中文Windows 10中,默认读入的是mbcs编码的文件名,需要decode成unicode,再encode成操作系统编码 files = os.listdir(dir.encode(sys.getfilesystemencoding())) for f in files: print f.decode(sys.getfilesystemencoding()).encode(encoding) guess_encoding() ls()