初探python编码
背景:在实际数据处理中,我们或多或少会接触到中文,如两个dc pack包的diff。使用python对中文数据 处理难免会遇到编码问题。
python里面主要考虑三种编码:
1、源文件编码:
如果我们在源文件中使用中文注释或中文docstring或中文字符串,如不明确指定应使用哪个中文字符集,解 释器将无法处理我们的程序。这是因为解释器默认程序使用的是ASCII或ISO-8859-1(即LATIN-1)编码。
解决方法是在文件头部使用coding声明(往往紧跟在#!注释行后面):
#coding: gbk
或# coding=gbk
或# -*- coding: gbk -*-
2、内部编码: python内部表示一个字符串有两种方式:一种是普通的str对象(基于字节的字符表示),另一种是unicode字符 串。它们之间可相互转换:
unicode转其他编码形式的str对象(encode):
>>> unicodestring = u"我爱你"
>>> unicodestring
u'\xce\xd2\xb0\xae\xc4\xe3'
>>> unicodestring.__class__ #另外使用isinstance(unicodestring, unicode)也可以查看是否是unicode字符串 >>> utf8string = unicodestring.encode("utf-8")
>>> utf8string
'\xc3\x8e\xc3\x92\xc2\xb0\xc2\xae\xc3\x84\xc3\xa3'
>>> utf8string.__class__ >>> isostring = unicodestring.encode("ISO-8859-1")
>>> isostring
'\xce\xd2\xb0\xae\xc4\xe3'
>>> isostring.__class__ >>> utf16string = unicodestring.encode("utf-16")
>>> utf16string
'\xff\xfe\xce\x00\xd2\x00\xb0\x00\xae\x00\xc4\x00\xe3\x00'
>>> utf16string.__class__
str对象转unicode(decode):
>>> unistring1 = unicode(utf8string, "utf-8")
>>> unistring1
u'\xce\xd2\xb0\xae\xc4\xe3'
>>> unistring1.__class__ >>> unistring2 = unicode(isostring, "ISO-8859-1")
>>> unistring2
u'\xce\xd2\xb0\xae\xc4\xe3'
>>> unistring2.__class__ >>> unistring3 = unicode(utf16string, "utf-16")
>>> unistring3
u'\xce\xd2\xb0\xae\xc4\xe3'
>>> unistring3.__class__
s.decode方法和u.encode方法是最常用的,
简单说来就是,python内部表示字符串用unicode(其实python内部的表示和真实的unicode是有点差别的,对我们几乎透明,可不考虑),和人交互的时候用str对象。
s.decode -------->将s解码成unicode,参数指定的是s本来的编码方式。这个和unicode(s,encodename)是一样的。
u.encode -------->将unicode编码成str对象,参数指定使用的编码方式。
助记:decode to unicode from parameter
encode to parameter from unicode
只有decode方法和unicode构造函数可以得到unicode对象。
上述最常见的用途是比如这样的场景,我们在python源文件中指定使用编码cp936,
# coding=cp936或#-*- coding:cp936 -*-或#coding:cp936的方式(不写默认是ascii编码)
这样在源文件中的str对象就是cp936编码的,我们要把这个字符串传给一个需要保存成其他编码的地方(比如xml的utf-8,excel需要的utf-16)
通常这么写:
strobj.decode("cp936").encode("utf-16")
3、外部编码: 一般不必要为字符串内在的表示担忧; 只有当尝试把Unicode传递给给一些基于字节的函数的时候,Unicode字符的表示 变成一个议题, 比如文件的write方法或网络套接字的send 方法。那时,你必须要选择该如何表示这些(Unicode) 字符为字节。从Unicode码到字节串的转换被叫做编码。同样地,当你从文件,套接字或其他的基于字节的对象 中装入一个Unicode字符串的时候,你需要把字节串解码为(Unicode)字符。
示例:
>>> f = open("/home/spider/atdc/data/alias/case1/pack", "r")
>>> data = f.read()
>>> data.__class__ >>> msg = u""
>>> msg += data
Traceback (most recent call last):
File "", line 1, in
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd5 in position 835: ordinal not in range(128)
msg被初始化为unicode字符串,而data是read函数返回的文件内容,是str对象,msg要粘结data就需要编码转换了:
>>> msg += unicode(data, "ISO-8859-1")
另外跟标准输出打交道时也需要考虑编码转换:
>>> print msg
Traceback (most recent call last):
File "", line 1, in
UnicodeEncodeError: 'ascii' codec can't encode characters in position 835-844: ordinal not in range(128)
有人建议重设sys的defaultencoding,是否能奏效呢?
>>> import sys
>>> reload(sys) >>> sys.setdefaultencoding('utf8')
>>> print msg
Traceback (most recent call last):
File "", line 1, in
UnicodeEncodeError: 'ascii' codec can't encode characters in position 835-844: ordinal not in range(128)
哦,跟之前一样的错误。那setdefaultencoding起了什么样的作用呢?继续看下面的示例:
>>> import sys
>>> sys.getdefaultencoding()
'ascii'
>>> u = u"我爱你"
>>> u
u'\xce\xd2\xb0\xae\xc4\xe3'
>>> u.decode("utf8") #unicode不能用utf8解码?!
Traceback (most recent call last):
File "", line 1, in
File "/home/spider/bin/lib/python2.6/encodings/utf_8.py", line 16, in decode
return codecs.utf_8_decode(input, errors, True)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
>>> reload(sys) >>> sys.setdefaultencoding('utf8')
>>> u.decode("utf8")
u'\xce\xd2\xb0\xae\xc4\xe3'
其 实unicode已经是python支持的最底层的字符串格式了,再对其解码的话就使用sys的defaultencoding对结果进行编码。 而reload之前sys的defaultencoding是ascii,ascii只支持0-127的英文字符串的编码格式,所以无法编码中文。而 reload 之后重设只是将解码后的unicode再用unicode编码,所以结果跟解码前的一样。
另外一些环境变量也会影响python的编码:
export LANG=zh_CN.gbk #之前LAGN=C
>>> u = u"我爱你"
>>> u
u'\u6211\u7231\u4f60'
>>> print u #这个时候就可以直接print了
我爱你
>>> s = "我爱你"
>>> s
'\xce\xd2\xb0\xae\xc4\xe3'
>>> print s
我爱你
>>> s.decode("gbk") #跟变量u的内容一样,说明此时的unicode是用gbk编码的
u'\u6211\u7231\u4f60'
>>> import sys
>>> sys.getdefaultencoding()
'ascii'
>>> sys.stdout.encoding
'GBK'
>>> sys.getfilesystemencoding()
'GBK'
外部编码更进一步的例子可以参考:http://blog.csdn.net/jiyucn/archive/2008/02/16/2100006.aspx
4、其他话题: (1)插入非法字符:
一个字符串中不一定都是统一编码的,如读取一个网页,head部分是utf8编码,而body部分却可能是gb编码,或者由于 截断的缘故一些字符串已经不完整了,这个时候再做编码操作就可能出错。如:
>>> s = "我爱你"
>>> s
'\xce\xd2\xb0\xae\xc4\xe3'
>>> serr = '\xce\xd2\xb0\xae\xc4\xe3\xa1'
>>> s.decode("gbk")
u'\u6211\u7231\u4f60'
>>> serr.decode("gbk")
Traceback (most recent call last):
File "", line 1, in
UnicodeDecodeError: 'gbk' codec can't decode byte 0xa1 in position 6: incomplete multibyte sequence
gbk无法编码第6个字符0xa1。这个时候我们可以指定decode的第2个参数为"ignore":
>>> serr.decode("gbk", "ignore")
u'\u6211\u7231\u4f60'
使用ignore可以忽视那些错误字符,可选项还有strict(缺省),replace(会替换成一个合适的字符,往往是编码集外 的字符),如:
export LANG=zh_CN.gbk
>>> serr = '\xce\xd2\xb0\xae\xc4\xe3\xa1'
>>> serr.decode("gbk", "replace")
u'\u6211\u7231\u4f60\ufffd'
>>> print serr.decode("gbk", "replace")
Traceback (most recent call last):
File "", line 1, in
UnicodeEncodeError: 'gbk' codec can't encode character u'\ufffd' in position 3: illegal multibyte sequence
对多数编码集来说字符u'\ufffd'都是非法字符。
(2)编码判断:
A、利用chardet识别编码:
#从标准输入读取字符串,重新编码,输出到标准输出 import sys
import chardet data=sys.stdin.read() incodec=chardet.detect(data)['encoding'] data=data.decode(incodec)
data=data.encode('utf-8')
sys.stdout.write(data)
唯一麻烦的是chardet不是python的标准库,需要自己手动安装。
B、利用系统信息,但会有例外:
import sys
reload(sys)
sys.setdefaultencoding('utf8') class OutputWrapper:
"""进行控制台输出编码转换的封装方案""" input_enc = sys.getdefaultencoding()
output_enc = sys.getfilesystemencoding() def __init__(self, target):
self.target = target
self.buffer = '' def flush(self):
self.target.flush() def write(self, message):
lines = message.split('\n')
lines[0] = self.buffer + lines[0]
self.buffer = lines.pop()
for line in lines:
try:
line = line.decode(self.input_enc).encode(self.output_enc) + '\n'
except:
line = line + '\n'
self.target.write(line) sys.stdout = OutputWrapper(sys.__stdout__)
sys.stderr = OutputWrapper(sys.__stderr__)
局限性:
1、这个方案只是简单的假设至少在字符串的每一行中,采用的是相 同的编码,或者是 sys.getdefaultencoding(), 或者是 sys.getfilesystemencoding()。 2、这个方案假设终端输出采用的编码和本地文件系统采用的编码是一样的(通常如此但总有例外)。
C、自己动手丰衣足食:
def zh2unicode(stri):
"""Auto converter encodings to unicode It will test utf8,gbk,big5,jp,kr to converter"""
for c in ('utf-8', 'gbk', 'big5', 'jp','euc_kr','utf16','utf32'):
try:
return stri.decode(c)
except:
pass
return stri
该函数将含中文字符的str对象转换为unicode,但是不知道哪种编码合适,就遍历地decode。局限性就在于遍历集不 一定全,而且遍历集过大的话会影响性能。
初探python编码的更多相关文章
- (转载) 浅谈python编码处理
最近业务中需要用 Python 写一些脚本.尽管脚本的交互只是命令行 + 日志输出,但是为了让界面友好些,我还是决定用中文输出日志信息. 很快,我就遇到了异常: UnicodeEncodeError: ...
- Python 编码简单说
先说说什么是编码. 编码(encoding)就是把一个字符映射到计算机底层使用的二进制码.编码方案(encoding scheme)规定了字符串是如何编码的. python编码,其实就是对python ...
- Python之路3【知识点】白话Python编码和文件操作
Python文件头部模板 先说个小知识点:如何在创建文件的时候自动添加文件的头部信息! 通过:file--settings 每次都通过file--setings打开设置页面太麻烦了!可以通过:View ...
- python编码规范
python编码规范 文件及目录规范 文件保存为 utf-8 格式. 程序首行必须为编码声明:# -*- coding:utf-8 -*- 文件名全部小写. 代码风格 空格 设置用空格符替换TAB符. ...
- 【转】python编码的问题
摘要: 为了在源代码中支持非ASCII字符,必须在源文件的第一行或者第二行显示地指定编码格式: # coding=utf-8 或者是: #!/usr/bin/python # -*- coding: ...
- 【转】python编码规范
http://blog.csdn.net/willhuo/article/details/49300441 决定开始Python之路了,利用业余时间,争取更深入学习Python.编程语言不是艺术,而是 ...
- python 编码 UnicodeDecodeError
将一个py脚本从Centos转到win运行,出错如下: UnicodeDecodeError: 'gbk' codec can't decode byte 0xff in position 0: il ...
- Python编码/文件读取/多线程
Python编码/文件读取/多线程 个人笔记~~记录才有成长 编码/文件读取/多线程 编码 常用的一般是gbk.utf-8,而在python中字符串一般是用Unicode来操作,这样才能按照单个字 ...
- 关于Python编码,超诡异的,我也是醉了
Python的编码问题,真是让人醉了.最近碰到的问题还真不少.比如中文文件名.csv .python对外呈现不一致啊,感觉好不公平. 没图说个JB,下面立马上图. 我早些时候的其他脚本,csv都是 ...
随机推荐
- kafka 命令笔记
以下命令都是在kafka根目录下 启动自带的zookeeper bin/zookeeper-server-start.sh config/zookeeper.properties 启动kafka(启动 ...
- nginx 服务器启动、终止、重启
启动 在linux系统下输入命令: nginx地址 -c nginx配置文件 就可启动nginx eg:/usr/local/nginx/sbin/nginx -c /usr/local/nginx/ ...
- Codeforces Round #380 (Div. 2)/729B Spotlights 水题
Theater stage is a rectangular field of size n × m. The director gave you the stage's plan which act ...
- CentOS安装JDK环境
一:查看当前系统的java环境 [elsearch@localhost data]$ rpm -qa | grep jdk 二:卸载原有的jdk [elsearch@localhost /]$ yum ...
- 希尔排序Shell sort
希尔排序Shell Sort是基于插入排序的一种改进,同样分成两部分, 第一部分,希尔排序介绍 第二部分,如何选取关键字,选取关键字是希尔排序的关键 第一块希尔排序介绍 准备待排数组[6 2 4 1 ...
- PHP扩展--Yaf框架安装
安装/配置 编译安装 wge thttp://pecl.php.net/get/yaf-2.3.5.tgz tar -zxvfyaf-2.3.5.tgz cd yaf-2.3.5/ cd extens ...
- Vuejs - 组件式开发
初识组件 组件(Component)绝对是 Vue 最强大的功能之一.它可以扩展HTML元素,封装可复用代码.从较高层面讲,可以理解组件为自定义的HTML元素,Vue 的编译器为它添加了特殊强大的功能 ...
- 重写strstr、strcpy、memcpy、memset、atof算法
#include<stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> ...
- Little Mathematics Knowledge 数学小常识
The sum of arithmetic sequence The sum of geometric sequence A special formula : n·n! = (n+1)! - n! ...
- 关于js闭包官方解释庖丁解牛式理解
闭包:是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. 变量+环境 首先按这个句子主谓宾来分解.闭包是一个表达式,通常是一个函数. 这意味着第一它 ...