文档章节

Python编码总结

guoliang
 guoliang
发布于 2015/02/13 14:24
字数 2080
阅读 18
收藏 0
点赞 0
评论 0

python中的unicode是让人很困惑、比较难以理解的问题,本文力求彻底解决这些问题;

 

1.unicode、gbk、gb2312、utf-8的关系;

http://www.pythonclub.org/python-basic/encode-detail 这篇文章写的比较好,utf-8是unicode的一种实现方式,unicode、gbk、gb2312是编码字符集;

 

2.python中的中文编码问题;

 2.1 .py文件中的编码

   Python 默认脚本文件都是 ANSCII 编码的,当文件 中有非 ANSCII 编码范围内的字符的时候就要使用"编码指示"来修正。 一个module的定义中,如果.py文件中包含中文字符(严格的说是含有非anscii字符),则需要在第一行或第二行指定编码声明:

# -*- coding=utf-8 -*-或者 #coding=utf-8 其他的编码如:gbk、gb2312也可以; 否则会出现类似:SyntaxError: Non-ASCII character '/xe4' in file ChineseTest.py on line 1, but no encoding declared; see http://www.pytho for details这样的异常信息;n.org/peps/pep-0263.html

 

2.2 python中的编码与解码

先说一下python中的字符串类型,在python中有两种字符串类型,分别是str和unicode,他们都是basestring的派生类;str类型是一个包含Characters represent (at least) 8-bit bytes的序列;unicode的每个unit是一个unicode obj;所以:

len(u'中国')的值是2;len('ab')的值也是2;

在str的文档中有这样的一句话:The string data type is also used to represent arrays of bytes, e.g., to hold data read from a file. 也就是说在读取一个文件的内容,或者从网络上读取到内容时,保持的对象为str类型;如果想把一个str转换成特定编码类型,需要把str转为Unicode,然后从unicode转为特定的编码类型如:utf-8、gb2312等;

python中提供的转换函数:

unicode转为 gb2312,utf-8等

# -*- coding=UTF-8 -*-

if __name__ == '__main__':
    s = u'中国'
    s_gb = s.encode('gb2312')

utf-8,GBK转换为unicode 使用函数unicode(s,encoding) 或者s.decode(encoding)

# -*- coding=UTF-8 -*-

if __name__ == '__main__':
    s = u'中国'

    #s为unicode先转为utf-8

    s_utf8 =  s.encode('UTF-8')

 

    assert(s_utf8.decode('utf-8') == s)

 

普通的str转为unicode

# -*- coding=UTF-8 -*-

if __name__ == '__main__':
    s = '中国'

    su = u'中国''

    #s为unicode先转为utf-8

    #因为s为所在的.py(# -*- coding=UTF-8 -*-)编码为utf-8

    s_unicode =  s.decode('UTF-8')

    assert(s_unicode == su)

    #s转为gb2312,先转为unicode再转为gb2312

    s.decode('utf-8').encode('gb2312')

    #如果直接执行s.encode('gb2312')会发生什么?

    s.encode('gb2312')

 

# -*- coding=UTF-8 -*-

if __name__ == '__main__':
    s = '中国'

    #如果直接执行s.encode('gb2312')会发生什么?

    s.encode('gb2312')

 

这里会发生一个异常:

Python 会自动的先将 s 解码为 unicode ,然后再编码成 gb2312。因为解码是python自动进行的,我们没有指明解码方式,python 就会使用 sys.defaultencoding 指明的方式来解码。很多情况下 sys.defaultencoding 是 ANSCII,如果 s 不是这个类型就会出错。 
拿上面的情况来说,我的 sys.defaultencoding 是 anscii,而 s 的编码方式和文件的编码方式一致,是 utf8 的,所以出错了: UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128) 
对于这种情况,我们有两种方法来改正错误: 
一是明确的指示出 s 的编码方式 
#! /usr/bin/env python 
# -*- coding: utf-8 -*- 
s = '中文' 
s.decode('utf-8').encode('gb2312') 
二是更改 sys.defaultencoding 为文件的编码方式 

#! /usr/bin/env python 
# -*- coding: utf-8 -*- 

import sys 
reload(sys) # Python2.5 初始化后会删除 sys.setdefaultencoding 这个方法,我们需要重新载入 
sys.setdefaultencoding('utf-8') 

str = '中文' 
str.encode('gb2312')

 

文件编码与print函数
建立一个文件test.txt,文件格式用ANSI,内容为:
abc中文
用python来读取
# coding=gbk
print open("Test.txt").read()
结果:abc中文
把文件格式改成UTF-8:
结果:abc涓枃
显然,这里需要解码:
# coding=gbk
import codecs
print open("Test.txt").read().decode("utf-8")
结果:abc中文
上面的test.txt我是用Editplus来编辑的,但当我用Windows自带的记事本编辑并存成UTF-8格式时,
运行时报错:
Traceback (most recent call last):
  File "ChineseTest.py", line 3, in <module>
    print open("Test.txt").read().decode("utf-8")
UnicodeEncodeError: 'gbk' codec can't encode character u'/ufeff' in position 0: illegal multibyte sequence

原来,某些软件,如notepad,在保存一个以UTF-8编码的文件时,会在文件开始的地方插入三个不可见的字符(0xEF 0xBB 0xBF,即BOM)。
因此我们在读取时需要自己去掉这些字符,python中的codecs module定义了这个常量:
# coding=gbk
import codecs
data = open("Test.txt").read()
if data[:3] == codecs.BOM_UTF8:
 data = data[3:]
print data.decode("utf-8")
结果:abc中文

(四)一点遗留问题
在第二部分中,我们用unicode函数和decode方法把str转换成unicode。为什么这两个函数的参数用"gbk"呢?
第一反应是我们的编码声明里用了gbk(# coding=gbk),但真是这样?
修改一下源文件:
# coding=utf-8
s = "中文"
print unicode(s, "utf-8")
运行,报错:
Traceback (most recent call last):
  File "ChineseTest.py", line 3, in <module>
    s = unicode(s, "utf-8")
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 0-1: invalid data
显然,如果前面正常是因为两边都使用了gbk,那么这里我保持了两边utf-8一致,也应该正常,不至于报错。
更进一步的例子,如果我们这里转换仍然用gbk:
# coding=utf-8
s = "中文"
print unicode(s, "gbk")
结果:中文
翻阅了一篇英文资料,它大致讲解了python中的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. For example, on Windows, it might be the Windows console subsystem that displays the result. Or if you're using Windows and running Python on a Unix box somewhere else, your Windows SSH client is actually responsible for displaying the data. If you are running Python in an xterm on Unix, then xterm and your X server handle the display.

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

简单地说,python中的print直接把字符串传递给操作系统,所以你需要把str解码成与操作系统一致的格式。Windows使用CP936(几乎与gbk相同),所以这里可以使用gbk。
最后测试:
# coding=utf-8
s = "中文"
print unicode(s, "cp936")
结果:中文

特别推荐:

python 编码 检测

使用 chardet 可以很方便的实现字符串/文件的编码检测

例子如下:

>>> import urllib >>> rawdata = urllib .urlopen ( 'http://www.google.cn/' ) .read ( ) >>> import chardet >>> chardet.detect ( rawdata) { 'confidence' : 0.98999999999999999 , 'encoding' : 'GB2312' } >>>

chardet 下载地址 http://chardet.feedparser.org/

特别提示:

在工作中,经常遇到,读取一个文件,或者是从网页获取一个问题,明明看着是gb2312的编码,可是当使用decode转时,总是出错,这个时候,可以使用decode('gb18030')这个字符集来解决,如果还是有问题,这个时候,一定要注意,decode还有一个参数,比如,若要将某个String对象s从gbk内码转换为UTF-8,可以如下操作 
s.decode('gbk').encode('utf-8′) 
可是,在实际开发中,我发现,这种办法经常会出现异常: 
UnicodeDecodeError: ‘gbk' codec can't decode bytes in position 30664-30665: illegal multibyte sequence 
这 是因为遇到了非法字符——尤其是在某些用C/C++编写的程序中,全角空格往往有多种不同的实现方式,比如/xa3/xa0,或者/xa4/x57,这些 字符,看起来都是全角空格,但它们并不是“合法”的全角空格(真正的全角空格是/xa1/xa1),因此在转码的过程中出现了异常。 
这样的问题很让人头疼,因为只要字符串中出现了一个非法字符,整个字符串——有时候,就是整篇文章——就都无法转码。 
解决办法: 
s.decode('gbk', ‘ignore').encode('utf-8′) 
因为decode的函数原型是decode([encoding], [errors='strict']),可以用第二个参数控制错误处理的策略,默认的参数就是strict,代表遇到非法字符时抛出异常; 
如果设置为ignore,则会忽略非法字符; 
如果设置为replace,则会用?取代非法字符; 
如果设置为xmlcharrefreplace,则使用XML的字符引用。 

python文档 

decode( [encoding[, errors]]) 
Decodes the string using the codec registered for encoding. encoding defaults to the default string encoding. errors may be given to set a different error handling scheme. The default is 'strict', meaning that encoding errors raise UnicodeError. Other possible values are 'ignore', 'replace' and any other name registered via codecs.register_error, see section 4.8.1. 
详细出处参考:http://www.jb51.net/article/16104.htm

参考:

【1】http://blog.chinaunix.net/u2/68206/showart.php?id=668359

【2】http://www.pythonclub.org/python-basic/codec

【3】http://www.pythonclub.org/python-scripts/quanjiao-banjiao

【4】http://www.pythonclub.org/python-basic/chardet

本文转载自:http://blog.csdn.net/dao123mao/article/details/5396497

共有 人打赏支持
guoliang
粉丝 26
博文 115
码字总数 27457
作品 0
杭州
程序员
[自动化实战」总结从python2.7和python3.0的语法差异

我的实战课《python自动化运维实战》经过了一年的设计,工程是基于python2.7版本开发而成。 Python 2/3的思想基本是共通的,只有少量的语法有差别甚至不兼容。当对Python熟悉到一定程度时, ...

幕客技术 ⋅ 01/14 ⋅ 0

深入浅出地,彻彻底底地理解python中的编码

作者:milter 链接:https://www.jianshu.com/p/eb22cee6c553 1问题1:问题在哪里? 问题是我们的靶子,心中没有问题去学习就会抓不住重点。 本文使用的编程环境是centos6.7,python2.7。 我...

机器学习算法与自然语言处理 ⋅ 05/02 ⋅ 0

使用chardet探测字符串编码

有时在使用python爬虫爬取页面时,返回的内容是乱码的,一种行之有效的方法是利用chardet(需要使用pip安装)探测字符串的编码,再相应调整爬虫的编码方式进行解码。示例如下: 1.利用request...

盗花 ⋅ 05/13 ⋅ 0

个人总结——全面的『Python编码规范』

本文目的 『动态类型一时爽,代码重构火葬场』,说的是:动态语言在初期开发比较爽,但是到后期维护起来比较困难。Python 作为动态语言之一,自然也会有这样的缺点。其实说『火葬场』,也没有...

hezhiming ⋅ 05/18 ⋅ 0

Python基础——内置hashlib、IO、Json、codecs模块(0426)

一、hashlib 加密模块:提供了很多加密的算法 常见的加密方式:MD5 RSA,加密之后不可逆。没法破解。 1、以MD5的方式加密字符串(Python 3) 示例 结果 2、以MD5的方式加密字符串(Python 2)...

python初雪之路 ⋅ 04/27 ⋅ 0

人人都能学会的python编程教程3:字符串和编码

字符串 在python3中已经全面支持中文。 由于Python源代码也是一个文本文件,所以,当你的源代码中包含中文的时候,在保存源代码时,就需要务必指定保存为UTF-8编码。当Python解释器读取源代码...

编程老司机 ⋅ 05/10 ⋅ 0

python中#!/usr/bin/python与#!/usr/bin/env python的区别

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

p柯西 ⋅ 06/15 ⋅ 0

《Python从小白到大牛》简介

本书是一部系统论述Python编程语言、OOP编程思想以及函数式编程思想的立体化教程(含纸质图书、电子书、教学课件、源代码与视频教程)。为便于读者高效学习,快速掌握Python编程方法。本书作...

tony关东升 ⋅ 05/29 ⋅ 0

Python 2 和 Python 3 主要区别有哪些(一)?

Guido(Python之父,仁慈的独裁者)在设计 Python3 的过程中,受一篇文章 “Python warts” 的影响,决定不向后兼容,否则无法修复大多数缺陷。---摘录自《流畅的Python》 你可能从来没有听说...

liuzhijun ⋅ 2017/08/02 ⋅ 0

老司机工作总结!零基础python小白学习编程一定要知道的那些技巧

今天又是一年一度的关键时刻:高考了。高考可谓是牵动着无数普通家庭的心。但是高考就是千军万马过独木桥,是一场没有硝烟的战争,有输有赢。可是高考跟战争不一样的是,高考就算失败也会有其...

Python学习 ⋅ 06/07 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

解决httpclient超时设置不生效的问题

最近公司有项目需要通过http调用第三方服务,且第三方服务偶有超时,故需要设置一定的超时时间防止不响应的情况出现。 初始设置如下: [java] view plain copy //超时设置 RequestConfig re...

Mr_Tea伯奕 ⋅ 9分钟前 ⋅ 0

过滤器Filter和拦截器HandlerInterceptor

过滤器 依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要...

hutaishi ⋅ 13分钟前 ⋅ 0

Redis入门详解(转)

Redis入门详解 Redis简介 Redis安装 Redis配置 Redis数据类型 Redis功能 持久化 主从复制 事务支持 发布订阅 管道 虚拟内存 Redis性能 Redis部署 Redis应用场景 Redis总结 Redis简介: Redi...

xiaoyaoyoufang ⋅ 26分钟前 ⋅ 0

说说javascript中的那些专业名词

DOM(Document Object Model) 文档对象模型 BOM(Browser Object Model) 浏览器对象模型 ECMA(European Computer Manufacturer's Association) 欧洲计算机制造商协会 W3C(World Wide Web Conso......

hang1989 ⋅ 45分钟前 ⋅ 0

Bootstrap Wizard 多步表单控件

废话 有一块需求是 有多步表单 点击下一步时触发验证一个范围内的表单,点击上一步或取消,清空表单并返回第一步,点击最后一步提交整个表单的 就找到了这个插件,本来自己写了一个原生的 fo...

无极之岚 ⋅ 今天 ⋅ 0

如何利用Spring Cloud构建起自我修复型分布式系统

利用Netflix所打造的组件及各类大家熟知的工具,我们完全可以顺利应对由微服务以及分布式计算所带来的技术挑战。 在过去一年当中,微服务已经成为软件架构领域一个炙手可热的新名词,而且我们...

harries ⋅ 今天 ⋅ 0

临近实习前的感想

再过两星期就要开始新的一段实习了,想想去年的这个时候也在实习,心中不免思绪万千,也一直想写对2017做个总结,但一直迟迟没有下笔。 2017年的春节,我就开始准备开学后找份实习。那时候就...

无精疯 ⋅ 今天 ⋅ 0

Spring AOP(面向切面编程)

Spring AOP概念: Spring AOP 可以劫持一个执行的方法,在方法执行之前或之后添加额外的功能。通常情况下,AOP把项目中需要在多处用到的功能,比如日志、安全和事物等集中到一个类中处理,而...

霍淇滨 ⋅ 今天 ⋅ 0

人工智能、机器学习、数据挖掘以及数据分析有什么联系?

人工智能是目前炙手可热的一个领域,所有的互联网公司以及各路大迦们纷纷表态人工智能将是下一个时代的革命性技术,可与互联网、移动互联网时代的变更相媲美;AlphaGo在围棋领域战胜人类最顶...

董黎明 ⋅ 今天 ⋅ 0

使用 vue-cli 搭建项目

vue-cli 是一个官方发布 vue.js 项目脚手架,使用 vue-cli 可以快速创建 vue 项目,GitHub地址是:https://github.com/vuejs/vue-cli 一、 安装 node.js 首先需要安装node环境,可以直接到中...

初学者的优化 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部