文档章节

Python编码问题

 梦回雪夜观花
发布于 2016/02/03 00:25
字数 1758
阅读 330
收藏 7

python的编码有点繁琐,在这里总结一下。

一、str与unicode

    python中有两种数据模型来支持字符串这种数据类型,str和unicode。它们的基类都是basestring。比如s = "中文"就是str类型的字符串,而u=u"中文"就是一个unicode类型的字符串。

    严格来说,str应该叫做字节串,它是unicode经过编码后的字节组成的序列。unicode是由str类型的字符串解码后得到,同时unicode也可以编码成str类型。

二、文件编码与头部编码声明

        python默认源代码文件是ascii编码,所以一旦出现不在ascii以外的字符(比如说中文字符)就会出现问题。所以如果在源代码中出现非ascii字符,需要在文件头部声明字符编码,声明凡是如下:

  # -*- coding: encoding -*-

        注意:这里声明的编码方式与最后文件存储的编码方式要一致!要一致!要一致!。

        (也就是说,头部的声明只是告诉python使用了encoding编码,至于最后编辑器保存的编码方式并不一定就是encoding。正确的做法是保证他们一致!正确的做法是保证他们一致正确的做法是保证他们一致!)

 原因:文件头部编码声明决定了python解析源码中的str的编码选择方式。比如头部声明的是utf-8编码,则代码中s="中文",python就会按照utf-8编码格式来解析。如果文件本身编码是gbk,而源码文件头部声明的编码是utf-8,这样如果源码中有中文就会有问题了,因为本身中文str存储是按照gbk编码来的,而python在解析str的时候又以为是utf-8编码,这样就会报SyntaxError: (unicode error) 'utf8' codec can't decode byte错误。

三、读写文件编码

        A)采用python的open()方法打开文件时。

        调用read()读取的是str,编码就是文件本身的编码。此时我们需要调用decode('文件本身编码')函数,将其从其本身的编码解码成unicode编码。

       调用write()写文件,

            1)如果参数是unicode编码字符串,则需要用指定编码encode该字符串,而不能直接write unicode编码字符串;

            2)如果write()参数是其他编码格式的str(不同于待写入文件编码),则需要先用该str的编码进行decode()成unicode编码字符串,然后再对该unicode字符串encode()成目标编码(待写入文件编码),然后在写                     入。

# -*- coding: utf-8 -*-

#头部声明的为utf-8
str_utf8 = '哈哈'

#unicode编码字符串
str_unicode = u'哈哈'

f = open('./gbktext.txt','w')

#将unicode成gbk
f.write(str_unicode.encode('gbk'))

#f.write(str_unicode)出错

#将utf-8解码成unicode,再编码成gbk
f.write(str_utf8.decode('utf-8').encode('gbk'))

f.close()

        B)为了保证编码正确常使用codecs模块,可以指定编码打开文件。

         调用read()读取的是unicode。

         调用write()写文件

               1)如果write()参数是unicode,则使用打开文件时的编码写入,

               2)如果write()参数是其他编码格式的str(不同于待写入文件编码),则需要先用该str的编码进行decode()成unicode编码字符串,然后在写入。

# -*- coding: utf-8 -*-
import codecs

def testCodecs():
    unicode_str = u"中文"
    #encode from unicode to utf-8
    utf8_str = unicode_str.encode('utf-8')
    #encode from unicode to gbk
    gbk_str = unicode_str.encode('gbk')
    
    filename = 'utf8_text.txt'
  
    wfp = codecs.open(filename, 'w', 'utf-8')
    
    #unicode字符串
    wfp.write(unicode_str)
    
    #先decode()成unicode
    wfp.write(gbk_str.decode('gbk'))
    
    wfp.flush()
    wfp.close() 
    
    #read file in utf-8
    rfp = codecs.open(filename, 'r','utf-8')
    str_type = rfp.read()
    
    #读出的类型是unicode ==> type(str_type) =  <type 'unicode'>  
    print 'type(str_type) = ',type(str_type)
    
if __name__ == "__main__":
    testCodecs()

四、其他注意事项

        1、windows控制台中文编码是GBK,Python的IDLE编码也是GBK

    

   

        但这里为什么不是中文字符"哈哈哈"而是'\xb9\xfe\xb9\xfe\xb9\xfe',其实这里输出的是“哈哈哈”的GBK编码的16进制形式(他是正确的)。为什么print的时候确实是"哈哈哈"?

    When Python executes a print statement, it simply passes the output to the operating system (using fwrite() or something like it), and some other program is responsible for actually displaying that output on the screen.

    To print data reliably, you must know the encoding that this display program expects.

    也就是说当调用print的时候它仅仅是将字符串传给了操作系统,至于如何显示是由其他的program负责的(比如windows终端,IDLE),负责显示的program会对传入的字符串进行编码。所以要想获得可靠的输出,必须要知道负责输出的program的编码(并与负责显示的program的编码一致)。

    print的时候显示是由python IDLE负责,也就是按GBK解释,打印自然是"哈哈哈"

    将其decode()的时候可以得到正确的unicode字符串 u'\u54c8\u54c8\u54c8',当print unicode字符串的时候,自动以GBK(负责显示的program所使用的编码) encode()然后显示,所以打印也是"哈哈哈"。

    也就是说要想获得正确的显示,必须保证print的字符串编码格式与终端(负责显示的终端编码格式)一致!

    但是,如果要显示的字符串中包含有负责显示program(如windows终端)所使用编码不会包含的字符会怎样?

    对,会出错。比如,当此unicode字符串中包含某特殊字符,而目标终端的编码集合中没有此字符,则很明显也是无法实现将Unicode编码为对应的特定编码的字符串,无法正确显示的。

# -*- coding: utf-8 -*-

slashUStr = "\\u3232\\u6674"; #(有) 晴

decodedUniChars = slashUStr.decode("unicode-escape");
#如果没有打印的刚性需求的话,我们完全可以选择不打印,直接进行下一步的处理
#因为此处已经可以正常获得对应的两个Unicode字符了,完全可以继续进行后续处理
unicodeButContainSpecialChar = decodedUniChars;

print "unicodeButContainSpecialChar=",unicodeButContainSpecialChar;

    他在Python IDLE中其实显示是正确的(原因不明,先忽略)。如果在windows 终端显示,会按预期的出错(#UnicodeEncodeError: 'gbk' codec can't encode character u'\u3232' in position 0: illegal multibyte sequence),因为他包含GBK字符集不包含的字符,
 Unicode字符:0x3232,是个特殊字符,而此字符,不在GBK编码字符集。

    但是还有一种办法可以解决。  

s.encode("gbk", "ignore");
#忽略掉无法正确编码的字符

#假设s试试utf-8编码,按gbk解码肯定有问题,若非要解码
s.decode('gbk','ignore')
#忽略掉无法正确解码的字符

2、windows记事本问题

        在window下面用记事本编辑文件的时候,如果保存为UNICODE或UTF-8,分别会在文件的开头加上两个字节“\xFF\xFE”和三个字节“\xEF\xBB\xBF”。在读取的时候就可能会遇到问题。(windows控制台,python shell下有问题,pythonIDLE正常)

    

# -*- coding: utf-8 -*-

f = open('./utf8.txt','r').read()

print f

print f.decode('utf-8')[1:]

    

   五、参考

        http://www.cnblogs.com/huxi/archive/2010/12/05/1897271.html

        http://www.crifan.com/python_already_got_correct_encoding_string_but_seems_print_messy_code/

        

        

© 著作权归作者所有

共有 人打赏支持
粉丝 8
博文 13
码字总数 16693
作品 0
武汉
程序员
python(一)变量,常量,编码,数据类型

首先,对于python开发环境,个人推荐使用eclipse+pydev,这样是极好的 O(∩_∩)O python同php一样都属于弱数据类型语言,因此在定义变量的时候,python同样不需要给出数据的类型,然后它比p...

Koma
2015/01/14
0
0
Python 2 和 Python 3 有哪些主要区别?

语法 print不再是语句,而是函数,比如原来是 print 'abc' 现在是 print('abc') 但是 python2.6+ 可以使用 from future import print_function 来实现相同功能 在Python 3中,没有旧式类,只...

cooffeelis
03/05
0
0
Python使用pip安装第三方库时出现UnicodeError的解决办法(Windows平台下)

博主最近在学习写爬虫,需要下载scrapy。可是先是解决了缺少VC++9.0问题之后,又总是报出UnicodeError问题。报错信息如下: UnicodeDecodeError: 'ascii' codec can't decode byte 0xba in ...

pasilo
06/28
0
0
python中#!/usr/bin/python与#!/usr/bin/env python的区别

目的是在运行python脚本的时候告诉操作系统我们要用python解释器去运行py脚本 所以我们在第一句往往会写如下两句中的其中一句: 或 就是说在没有在执行程序时指出用什么程序运行py脚本时,系统...

p柯西
06/15
0
0
Requests 库编码问题及引出的 Python 编码问题

Requests 编码 在使用 requests 访问微信接口的时候,requests 只根据 http headers 的信息来设置编码集,文档如下: 这边就是说,我们的选择还有,当服务器不指定编码集时,使用以下方式指定...

xh4n3
2015/08/12
0
0

没有更多内容

加载失败,请刷新页面

加载更多

分布式缓存架构设计

零、 题记 在高并发场景下,需要通过缓存来减少数据库的压力,使得大量的访问进来能够命中缓存,只有少量的需要到数据库层。由于缓存基于内存,可支持的并发量远远大于基于硬盘的数据库。所以...

Ala6
29分钟前
2
0
简单工厂模式

public abstract class Operation { private double numberA = 0; private double numberB = 0; public double getNumberA() { return numberA; } ......

NinjaFrog
31分钟前
1
0
git(一) 基本操作(branch、tag、冲突)

layout: blog istop: true title: "git基本操作(branch、tag、冲突)" date: 2018-09-11 category: 版本控制 tags: - 版本控制 撤销操作 修改最后一次提交 解释:修改上次提交。可以修改内容...

开心的哈士奇
34分钟前
1
0
Vue中路由管理器Vue Router使用方式(二)-推荐

一、Vue中使用Vue Router简单方式使用 vue add xxx命令添加插件 使用步骤,本人假设已经安装好了Vue CLI工具,了解更多参考:VSCode 搭建Vue开发环境之Vue CLI 1.创建项目 vue create hello...

tianma3798
46分钟前
1
0
设计模式(十六)[结构模式] 装饰模式(Decorator)

1.什么是装饰模式? 装饰模式又名包装模式。装饰模式以对客户端透明的方式扩展对象功能,是继承关系的一个替代方案。 2.模式的类图 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收...

1527
47分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部