python中的编码 encode decode setdefautendcoding write print

目录

永远记住计算机存储的是二进制码流,不是文字
涉及编码的几个函数的理解
unicode 与 print函数
write使用示例
常见的错误1:write使用错误
常见的错误2:encode错误
常见的错误2: utf-8 与 utf-8 无BOM
常见的错误4: 对unicode进行decode错误
常见的错误5:对函数‘==’和replace的理解


永远记住计算机存储的是二进制码流,不是文字
python 中的中文乱码经常地很让人头疼。

其实所谓编码,就是一种数字(编码数字)与文字的一一映射关系。之所以会有不同的编码,就是这种映射关系不唯一。计算机里存储的是编码的数字,形式上就是二进制流,由于这种映射关系不唯一,所以一个文本经不同的编码总会得到不同的二进制流。

涉及编码的几个函数的理解
python中经常会涉及编码的几个函数和我个人对他们的理解(理解没经过查证,只是单纯的通过实现验证,请小心参考):

函数 功能 编码错误产生可能
s.encode(‘utf-8’) 如果s是str类型,将二进制码流B1按系统默认编码对应出相应的文字,再将相应的文字按utf-8获新的二进制码流B2;
如果s是unicode类型,将二进制流B1按unicode编码对应出相应的文字,再将相应的文字按utf-8获新的二进制码流B2;
该函数返回书类型为str
s为str类型时,B1不是使用系统编码获得的
s.decode(‘utf-8’) 将s的二进制码流B1按utf-8获取相应的文字,相应的文字按unicode获取新的二进制码流B2;
该函数返回类型是unicode
B1不是使用utf-8编码获得的
setdefaultencoding(‘utf-8’) 设置系统默认编码为utf-8,默认为ascii
write(s) 如果s类型是str,那么直接写入文件,如果s是unicode,将s对应的二进制码流按unicode获得相应文字,再将相应文字按系统默认编码获取新的二进制码流,将s对应的二进制码流改写为这个新的二进制码流
print(s) 将s的二进制码流按unicode获取相应的文字,输出到屏幕上(在我的windows8.1系统上print好像还能正常解析gbk编码)
函数 功能 编码错误产生可能
encode(‘utf-8’) 将系统默认编码或unicode编码对应的二进制流B1转化为utf-8编码的二进制流B2 B1不是使用系统编码获得的
decode(‘utf-8’) 将使用utf-8的二进制流B1转化为unicode编码的二进制流B2 B1不是使用utf-8编码获得的

注:ANSI格式不是ascii编码,而是gbk编码(查看notepad++)

这几个函数使用不慎,就会出现中文乱码。

unicode 与 print函数
python 中除了str,还有unicode类型表示字符串

对于print函数,如果是字符流,他会输出对应的Unicode文字;如果是一个与list,那么将输出这个list里字符的编码二进制流(实质是十六进制数)

#coding=utf-8
# 下面三种方式获得结果以一样的(输出的文字和二进制码流)
s = unicode('中国', 'utf-8')
print s, [s]                            # 中国 [u'\u4e2d\u56fd']
s = u'中国'                           # 这个可能是解释器根据文件本身coding=utf-8的编码进行了隐式的准换吧
print s, [s]                            # 中国 [u'\u4e2d\u56fd']
s = '中国'.decode('utf-8')
print s, [s]                           # 中国 [u'\u4e2d\u56fd']

write使用示例

#coding=utf-8
# write
def test1():
    filep = open('test.txt','wb')
    s = '你是谁'                    # 这里s的二进制流对应的是该文件的编码,因为指定了事utf-8编码,所以这里对应的是utf-8对应的流
    filep.write(s)                   # s的类型是str,所以写入文件的的是utf-8对应的二进制流
    filep.close()

    words = open('test.txt','rb').read()
    print words == s                # True。True。 因为读文件读的是二进制流没有发生改变
    print s                         # 乱码。print会按unicode编码解析这个utf-8对应的二进制流
    print s.decode('utf-8')         # 无乱码。先试用decode把utf-8的二进制流转化为 unicode的二进制流,再利用print按unicode编码解析这个流得到最终对应的文字。

该程序生成的test.txt使用notepad++打开,格式选为以utf-8编码,就能看到正确的内容
test.txt

常见的错误1:write使用错误

# coding=utf-8
def test2():
    filep = open('test.txt','wb')
    s = u'你是谁'                   # s存储的是unicode对应的二进制流
    filep.write(s)                   # Error 解释报错。write接收到unicode流,先将unicode流转化为系统编码(默认为ascii)流,ascii无法编码中文,报错
    filep.close()

报错如下

    UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)

报错分析:

s的二进制流是unicode'你是谁'的编码,write接收到unicode类型后,
会将二进制流按unicode的编码对应出相应的文字('你是谁'),
然后将相应的文字('你是谁')按系统默认编码(如果不设置,就是ascii)对应出相应的二进制流编码,
由于ascii无法对汉字进行编码所以出错了。

解决方案:
修改系统默认编码方式

 # coding=utf-8
def test2_change():
import sys
reload(sys)
sys.setdefaultencoding( "utf-8" )  # 临时修改系统默编码方式,程序结束后失效
filep = open('test.txt','wb')
s = u'你是谁'                         # s存储的是unicode对应的二进制流
filep.write(s)                     # write接收到unicode流,先将unicode流转化为系统编码(前面已修改为utf-8)流,再写入文件
filep.close()

常见的错误2:encode错误

#coding=utf-8
# 首先字符串'中文'在这个utf-8的文件里先得到utf-8流,
# encode('gbk') 先将utf-8流按系统默认编码(ascii)对应出文字,再将文字对应到utf-8对应的二进制流
# 但是ascii无法编码中文,所以在encode的第一步就会报错。即使能编码中文,对utf-8流使用非utf-8对应文字,也会是乱码。
def test3():
    s = '中文'.encode('gbk')          # Error。

正确修改为,修改系统默认编码和文件编码一致

def test3_change():
    import sys
    reload(sys)
    sys.setdefaultencoding('utf-8')     # 临时修改系统默编码方式,程序结束后失效
    s = '中文'.encode('gbk')          # utf-8流按系统默认方式utf-8对应出文字,将文字按gbk对应出gbk二进制码流

    print s.decode('gbk')               # 将gbk二进制流按gbk对应出文字,再将文字按unicode对应出unicode二进制码流
                                        # print再将unicode码流按unicode对应出文字打印出来
    print s                             # 这个没有乱码,说明在我这台机器上,print可以正常打印gbk流
    print [s], [s.decode('gbk')]

常见的错误2: utf-8 与 utf-8 无BOM

# utf-8无BOM 和 utf-8
# 有些编辑器在创建UTF8编码文件时会在头部添加一个不可见字符(这个例子里是0xfeff)
# 这个被称作BOM(Byte Order Mark)的不可见字符,是Unicode用来标识内部编码的排列方式的,
# 在UTF-16、UTF-32编码里它是必需的,而在UTF-8里是可选的
# 如果utf-8文件是有BOM的那么应该从index=1开始读取,而不是index=0
def test4():
    import sys
    reload(sys)
    sys.setdefaultencoding( "utf-8" )       # 临时修改系统默编码方式,程序结束后失效
    w = open("hongloumeng.txt",'rb').read();
    w = w.decode("utf-8")                   # 注意变成unicode后不能使用replace,所以选择时机decode
    print w[1:7] == u" 上卷 第一"           # 从第1个开始的正文
    #print w[0:7]                           # w.worlds[0]打印会报错 【unicodeError】
    print [w[0]]            

hongloumeng.txt

常见的错误4: 对unicode进行decode错误

u'您好'.decode('utf-8')                           
'你好'.decode('utf-8').decode('utf-8')

以上两个都回报下面的错误:

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-12: ordinal not in range(128)

如果我的理解decode(‘utf-8’)是将二进制码流按utf-8对应出文字,所以将unicode二进制码流按utf-8对应文字时,自然会出错,但是应该报utf-8 codec的错误才对,这里却报了acsii codec的错误,看来我的理解虽然能解决遇到的问题,但还是有问题的。

常见的错误5:对函数‘==’和replace的理解
字符串比较s1==s2,
如果两者类型都是str,那么相等的条件是两者编码一致并且对应文字相同;
如果一个是str,另一个是unicode,那么会先将str按系统默认编码decode为unicode,再比较,相当于str.decode(defaultencoding)==unicode

#coding=utf-8
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

s0 = "我是中国人,我热爱学习"  # utf-8流
s1 = s0.decode('utf-8')         # unicode流
s2 = s1.encode('gbk')           # gbk流
print [s0,s1, s2]
print s0 == s2                  # False.  str1==str2 要求两者对应的文字相同并且编码一致 
print s0 == s1                  # True.   str==unicode 等价为 str.decode(defaultencoding)==unicode,因为默认编码设置为utf-8,所以True
print s1 == s2                  # False而且有Warning..   str==unicode 同上,但是默认编码是utf-8,而这个流是gbk流,所以转换为unicode失败

replace里字符匹配上了就是利用上面的标准s1==s2
所以如果是unicode.replace(str,..)或str.replace(unicode,…)系统默认编码设置会很重要;
如果是str.replace(str..)的话要保证两个str的bain吗要保持一致。

#coding=utf-8
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

# str.replace(str,...)
s = s0.replace('我', '我们').decode('utf-8')       # 一定可以 (文件编码和s0都符合utf-8)
print s, type(s), [s]
# unicode.replace(unicode,...)
s = s0.decode('utf-8').replace(u'我', u'我们')     # 一定可以 (文件编码和s0都符合utf-8)
print s, type(s), [s]
# unicode.replace(str,..)
s = s0.decode('utf-8').replace('我', '我们')       # (文件编码和s0都符合utf-8,还要保证系统默认编码是utf-8),否则就会失效甚至报错
print s, type(s), [s]
# str.replace(unicode,...)
s = s0.replace(u'我', u'我们').decode('utf-8')     # 同上一个
print s, type(s), [s]

测试源代码可参考:http://download.csdn.net/detail/yinglang19941010/9590911

猜你喜欢

转载自blog.csdn.net/yinglang19941010/article/details/52076978