python中文编码问题实例详解

发布时间:2020-02-24编辑:脚本学堂
本文介绍了python中文编码的一些问题与解决方法,在python源码中使用中文字符,运行时会有错误,需要在源码的开头部分加入字符编码的声明,需要的朋友参考下。
python中文编码问题实例详解 第二部分
六、跨平台处理技巧
如果一个project必须在两个平台上开发,程序应该使用同样的encoding,比如要求所有的文件都使用UTF-8,如果实在不能统一(一般是为了满足许多所谓专家学者莫名其妙的要求),可以退而求其次,用当前系统编码决定文件内的编码:
 

复制代码 代码示例:
import locale
import string
import re
#根据当前系统的encoding构造需要的编码取值
lang = string.upper(locale.setlocale(locale.LC_ALL, ""))
textencoding = None 3
#检查编码的值是不是满足我们需要的情况
if re.match("UTF-8", lang) != None:
# UTF-8编码
textencoding = "utf-8"
elif re.match(r"CHINESE|CP936", lang):
# Windows下的GB编码
textencoding = "gb18030"
elif re.match(r"GB2312|GBK|GB18030", lang):
# linux下的GB编码
textencoding = "gb18030"
else:
# 其他情况,抛个错误吧
raise UnicodeError
fd = file(filename, "r")
fulltextlist = fd.readlines()
# 把每一行转换成unicode
for each in len(fulltextlist):
fulltextlist[i] = unicode(each, textencoding)
fd.close()
# 如果要打印的话,可以用text.encode(encoding)来恢复成多字节编码

七、异常处理
编码encoding发生在Unicode字符串转换为字节序列时,而解码decoding发生在字节序列转换为Unicode字符串时(encoding always takes a Unicode string and returns a bytes sequence, and decoding always takes a bytes sequence and returns a Unicode string)。

UnicodeDecodeError
UnicodeDncodeError通常发生在将str字符串解码为特定Unicode字符串时。由于不同的编码只能映射部分str字符串到对应的Unicode字符,所以遇到一些字符时解码会失败。

UnicodeEncodeError
UnicodeEncodeError通常发生在将Unicode字符串编码为特定字节序列时。由于不同的编码只能映射部分Unicode字符到对应的str字符串,所以遇到一些字符时编码会失败。

处理python编码转换时的UnicodeDecodeError异常
python提供的unicode转换不像iconv或是mbstowcs之类的方便。如果转换一段unicode("1234中文",'ascii') 到utf8,会直接出现UnicodeDecodeError的错误。
如果在能预知字串符的编码时,比如用unicode('1234中文', 'gbk') 就不会出现错误;
不过很多时候,会出现CJK混合的情况,如果要做到将一段CJK文件转换成unicode可能就行不通了。好在python的codecs提供了register_error这个功能:
register_error(name, error_handler)
原理很简单,不过要先看unicode是如何处理异常的。unicode这个函数是将一段string按输入的编码转换成目标的编码,如果出现了不与输入编码相符的,会出现一个UnicodeDecodeError的异常,通常有三种处理方法:strict、replace、ignore;默认是 strict,就是直接raise UnicodeDecodeError。

通过register_error,也可以有自己的处理方法,如果遇到与输入的编码不符时,就自己识别,比如GBK、BIG5、JP的字符。
 

复制代码 代码示例:
def cjk_replace(exc):
if not isinstance(exc, UnicodeDecodeError):
raise TypeError("don't know how to handle %r" % exc)
if exc.end + 1 > len(exc.object):
raise TypeError('unknown codec ,the object too short!')
ch1 = ord(exc.object[exc.start:exc.end])
newpos = exc.end + 1
ch2 = ord(exc.object[exc.start + 1:newpos])
sk = exc.object[exc.start:newpos]
if 0x81<=ch1<=0xFE and (0x40<=ch2<=0x7E or 0x7E<=ch2<=0xFE): # GBK
return (unicode(sk,'cp936'), newpos)
if 0x81<=ch1<=0xFE and (0x40<=ch2<=0x7E or 0xA1<=ch2<=0xFE): # BIG5
return (unicode(sk,'big5'), newpos)
raise TypeError('unknown codec !')
codecs.register_error("cjk_replace", cjk_replace)
 

我们的cjk_replace现在只能处理GBK与BIG5的,因为我对编码也不是特别了解,只是大概知道GBK与BIG5的,不太了解JP的。在 cjk_replace这个函数里,我们对不认识的文字进行手工识别,如果认识的编码,就用正确的方法,并返回编码后的内容与新的pos,比如“1234中文”,在pos为4时,会调用我们的cjk_replace,我们会返回一个从gbk转换成utf8的“中”字,并返回下个正确的位置“文”的起始位置。当然了,处理“文”时,还会再调用一次。

下面看看是如何使用的:
 

复制代码 代码示例:
filedata = open('test.txt','r).read() #gbk and big5 file
data = unicode(filedata,'ascii','cjk_replace').encode('utf8')

小结
一个比较一般的Python中文处理的流程:
* 将欲处理的字符串用unicode函数以正确的编码转换为Unicode
* 在程序中统一用Unicode字符串进行操作
* 输出时,使用encode方法,将Unicode再转换为所需的编码
有几点要说明一下:
* 所谓“正确的”编码,指得是指定编码和字符串本身的编码必须一致。这个其实并不那么容易判断,一般来说,我们直接输入的简体中文字符,有两种可能的编码:GB2312(GBK、GB18030)、以及UTF-8
* encode成本地编码时,必须要保证目标编码中存在欲转换字符的内码。encode这种操作一般是通过一个本地编码对应Unicode的编码转换表来进行的,事实上每个本地编码只能映射到Unicode的一部分。但是映射的区域是不同的,比如Big-5对应的Unicode的编码范围和 GBK对应的就不一样(实际上这两个编码有部分范围是重叠的)。(www.jb200.com 脚本学堂)

所以,Unicode的一些字符(比如本身就是从GB2312转换来的那些),可以映射到 GBK,但未必可以映射到Big-5,如果你想转换到Big-5,很有可能就会出现编码找不到的异常。但UTF-8的码表范围实际上和Unicode是一样的(只是编码形式不同而已),所以,理论上来说,任何本地编码的字符,都可以被转换到UTF-8
* GB2312、GBK、GB18030本质上是同一种编码标准。只是在前者的基础上扩充了字符数量
* UTF-8和GB编码不兼容
* 出现编解码异常时可能需要自己编写编解码解析函数,这需要了解一些字符编码的知识

八、最后附一些关于 python 编码问题的总结:

1、写的代码模块需要指定编码
如果代码没有指定coding,python就默认所有的字符为ASCII码,
ASCII码只支持256个字符,ASCII码不支持中文,所以就报错。
所以要在代码前写上#coding:utf-8或#coding:gbk
建议代码统一写成这样:
 

复制代码 代码示例:
#coding:utf-8
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

2、python2内部所有编码统一为unicode
unicode可以处理世界上所有语言的字符。
utf-8为unicode的一种实现形式,所以需要在代码前写上#coding:utf-8

3、编码转换
牢记python2内部编码为unicode.
其它的编码decode()为unicode,再编码encode()为你指定的编码,就不会出现乱码

4、网页采集时
代码指定#coding:utf-8
如果网页的编码为gbk
需要这样处理:
 

复制代码 代码示例:
html = html.decode('gbk').encode('utf-8')

5、代码前也可以写#coding:gbk,但也要保证你的代码文件的保存格式为gbk.这个在windos下会出现这样的问题。

6、字典等key或值的汉字问题
 

复制代码 代码示例:

#coding:utf-8
dict1 ={1:'python周末培训班',2:'咨询010-68165761 QQ:1465376564'}

print dict1
# 这样输出的没有显示汉字,是显示汉字的其它编码

dict2 ={1:'python视频培训班',2:'咨询010-68165761 QQ:1465376564'}
for key in dict2:
    print dict2[key]

7、unicode的汉字编码写到文本文件中
需要根据文本文件的编码进行转换
 

复制代码 代码示例:
可以encode('utf-8')或encode('gbk')

总结:凡是报错信息中出现的错误包含“ASCII”,就是没有指定汉字编码的问题。