您的位置:首页 > 编程语言 > Python开发

python的str和unicode以及编码的问题

2017-06-24 20:36 651 查看
python的str和unicode处理

Python内部有一个unicode对象,所以python的内置编码为unicode编码。如果你的源代码文件为utf-8编码,那么请你在你的源代码第一行加上 -- coding:utf-8 -- 这一句,以告诉python解释器,你的源代码是用utf-8编码的。你的字符串也就是str,是utf-8编码的。那么你在处理的时候,就要用decode(‘utf-8’),来创建一个unicode对象。

x = ‘中’ #x为str类型,是utf-8 编码的

y = x.decode(‘utf-8’) #y为unicode类型,是unicode编码的对象

unicode和str在python中是两个不同的数据类型,看例子:

x = '中国'
print repr(x[0])
'\xe4'
y = x.decode('utf-8')
print repr(y[1])
u'\u56fd'


python的str,unicode对象都有encode和decode方法。

python中的str对象其实就是”8-bit string” ,字节字符串,本质上类似java中的byte[]。而python中的unicode对象应该才是等同于java中的String对象,或本质上是java的char[]。

1. s.decode方法和u.encode方法是最常用的,

简单说来就是,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对象。

2.

第一条已经写了不少,因为是最常用到的,基本不用怎么解释。我重点想说的是这第二条。

似乎有了unicode对象的encode方法和str的decode方法就足够了。奇怪的是,unicode也有decode,而str也有

encode,到底这两个是干什么的。

用处1

str本身已经是编码过的了,如果再encode很难想到有什么用(通常会出错的)

先解释下这个

str.encode(e) is the same as unicode(str).encode(e).

This is useful since code that expects Unicode strings should also work when it is passed

ASCII-encoded 8-bit strings(from Guido van Rossum)

python之父的这段话大概意思是说encode方法本来是被unicode调的,但如果不小心被作为str对象的方法调,并且这个str对象正好

是ascii编码的(ascii这一段和unicode是一样的),也应该让他成功。这就是str.encode方法的一个用处(我觉得这个基本等于没用)

类似地,把光用ascii组成的unicode再decode一回是一样的道理,因为好像几乎任何编码里ascii都原样没变。因此这样的操作等于没做。

u”abc”.decode(“gb2312”)和u”abc”是相等的。

用处2

非字符的编码集non-character-encoding-codecs,这些只在python中定义,离开python就没意义(这个来自python的官方文档)

并且也不是人类用的语言,呵呵。 比如:

'\n'.encode('hex')=='0a'
u'\n'.encode('hex')=='0a'
'0a'.decode('hex')=='\n'
u'0a'.decode('hex')=='\n'
'\n'.encode('hex')=='0a'
u'\n'.encode('hex')=='0a'
'0a'.decode('hex')=='\n'
u'0a'.decode('hex')=='\n'


可见名为hex的编码可以讲字符表示(当然了,必须是ascii内的)和十六进制表示之间转换 。另外还有很多好玩的,比如:base64通俗的讲是号称防君子不防小人的给邮件的编码,gzip大概是指压缩吧(这是我猜的),rot13回转13等,不知者google之 关于这些,官方有个详细的表格,在http://docs.python.org/library/codecs.html中的Standard Encodings一节中,前一个表格是基于字符的编码,第二个表格 就是这里的非字符的编码。关于这些特殊编码,官方一句说明:For the codecs listed below, the result in the “encoding” direction is always a byte string.

The result of the “decoding” direction is listed as operand type in the table.

encode的结果一定是一个byte的str,而decode的结果在表中operand一列。

编码声明的作用请参考http://www.python.org/dev/peps/pep-0263/声明源文件中将出现非ascii编码;在高级的IDE中,IDE会将你的文件格式保存成你指定编码格式。决定源码中类似于u’哈’这类声明的将’哈’解码成unicode所用的编码格式,也是一个比较容易让人迷惑的地方。(java不需要声明的原因在于:java中默认是本地编码而py中默认是ascii,搞得python更易出错,并且,java编译的时候还有个指定编码的参数encoding)

文件的编码格式决定了在该源文件中声明的字符串的编码格式,例如:

str = '哈哈'
print repr(str)
str = '哈哈'
print repr(str)


a.如果文件格式为utf-8,则str的值为:’\xe5\x93\x88\xe5\x93\x88’(哈哈的utf-8编码)

b.如果文件格式为gbk,则str的值为:’\xb9\xfe\xb9\xfe’(哈哈的gbk编码)

我的理解:文件编码格式保存后没有地方指明,只有靠聪明或笨的编辑器,编译器去猜。而声名就更精确一些。让两者一致了总不会错。

python模块之codecs

Python对多国语言的处理是支持的很好的,它可以处理现在任意编码的字符,这里深入的研究一下python对多种不同语言的处理。有一点需要清楚的是,当python要做编码转换的时候,会借助于内部的编码,转换过程是这样的:

原有编码 -> 内部编码 -> 目的编码

python的内部是使用unicode来处理的,但是unicode的使用需要考虑的是它的编码格式有两种,一是UCS-2,它一共有65536个码 位,另一种是UCS-4,它有2147483648g个码位。对于这两种格式,python都是支持的,这个是在编译时通过–enable- unicode=ucs2或–enable-unicode=ucs4来指定的。那么我们自己默认安装的python有的什么编码怎么来确定呢?有一个 办法,就是通过sys.maxunicode的值来判断:

import  sys
print  sys.maxunicode


如果输出的值为65535,那么就是UCS-2,如果输出是1114111就是UCS-4编码。

我们要认识到一点:当一个字符串转换为内部编码后,它就不是str类型了!它是unicode类型:

a  =   " 风卷残云 "
print  type(a)
<type 'str'>
b  =  decode('utf-8')
print  type(b)
<type 'unicode'>


# -*- encoding: gb2312 -*-
import  codecs, sys

print   ' - ' * 60
#  创建gb2312编码器
look   =  codecs.lookup( " gb2312 " )
#  创建utf-8编码器
look2  =  codecs.lookup( " utf-8 " )
a  =   " 我爱北京 "
print  len(a), a
#  把a编码为内部的unicode, 但为什么方法名为decode呢,我 的理解是把gb2312的字符串解码为unicode
b  =  look.decode(a)
#  返回的b[0]是数据,b[1]是长度,这个时候的类型是unicode 了
print  b[ 1 ], b[0], type(b[0])
#  把内部编码的unicode转换为gb2312编码的字符 串,encode方法会返回一个字符串类型
b2  =  look.encode(b[0])
#  发现不一样的地方了吧?转换回来之后,字符串长度由14变为了7! 现在 的返回的长度才是真正的字数,原来的是字节数
print  b2[ 1 ], b2[0], type(b2[0])
#  虽然上面返回了字数,但并不意味着用len求b2[0]的长度就是7了, 仍然还是14,仅仅是codecs.encode会统计字数
print  len(b2[0])


上面的代码就是codecs的使用,是最常见的用法。另外还有一个问题就是,如果我们处理的文件里的字符编码是其他类型的呢?这个读取进行做处理也需要特 殊的处理的。codecs也提供了方法:

# -*- encoding: gb2312 -*-
import  codecs, sys
#  用codecs提供的open方法来指定打开的文件的语言编码,它会在读 取的时候自动转换为内部unicode
bfile  =  codecs.open( " dddd.txt " ,  ' r ' ,  " big5 " )
# bfile = open("dddd.txt", 'r')
ss  =  bfile.read()
bfile.close()
#  输出,这个时候看到的就是转换后的结果。如果使用语言内建的open函数 来打开文件,这里看到的必定是乱码
print  ss, type(ss)


上面这个处理big5的,可以去找段big5编码的文件试试。

字符的编码是按照某种规则在单字节字符和多字节字符之间进行转换的某种方法。从单字节到多字节叫做decoding,从多字节到单字节叫做 encoding。在这些规则中经常用到的无非是UTF-8和GB2312两种。

在Python中,codecs模块提供了实现这些规则的方法,通过模块公开的方法我们能够方便地获取某种编码方式的Encoder和 Decoder工厂函数(Factory function),以及StreamReader、StreamWriter和StreamReaderWriter类。

使用“import codecs”导入codecs模块。

codecs模块中重要的函数之一是lookup,它只有一个参数encoding,指的是编码方式的名称,即utf-8或者gb2312等 等。如下示例:

>>> import codecs
>>> t = codecs.lookup("utf-8" )
>>> print t
(<built-in function utf_8_encode>, <function decode at 0x00AA25B0>, <class encodings.utf_8.StreamReader at 0x00AA0720>, <class encodings.utf_8.StreamWriter at 0x00AA06F0>)
>>> encoder = t[0]
>>> decoder = t[1]
>>> StreamReader = t[2]
>>> StreamWriter = t[3]


lookup函数返回一个包含四个元素的TUPLE,其中t[0]是encoder的函数引用,t[1]是decoder的函数引用,t[2] 是UTF-8编码方式的StreamReader类对象引用,t[3]是UTF-8编码方式的StreamWriter类对象引用相信对Python熟悉 的你肯定知道接下来该怎么用它们了。

codecs模块还提供了方便程序员使用的单独函数,以简化对lookup的调用。它们是:

getencoder(encoding)

getdecoder(encoding)

getreader(encoding)

getwriter(encoding)

如果我们只是想获取一种utf-8编码的encoder方法,那么只需要这样做:

>>> encoder = codecs.getencoder("utf-8" )


另外,对于StreamReader和StreamWriter的简化, codecs模块提供一个open方法。相对于built-in对象File的open方法,前者多了三个参数encoding, errors, buffering。这三个参数都是可选参数,但是对于应用来说,需要明确指定encoding的值,而errors和buffering使用默认值即 可。使用方法如下:

>>> fin = codecs.open("e://mycomputer.txt" , "r" , "utf-8" )
>>> print fin.readline()
这是我的电脑
>>> fin.close()


总结一下,codecs模块为我们解决的字符编码的处理提供了lookup方法,它接受一个字符编码名称的参数,并返回指定字符编码对应的 encoder、decoder、StreamReader和StreamWriter的函数对象和类对象的引用。为了简化对lookup方法的调用, codecs还提供了getencoder(encoding)、getdecoder(encoding)、getreader(encoding)和 getwriter(encoding)方法;进一步,简化对特定字符编码的StreamReader、StreamWriter和 StreamReaderWriter的访问,codecs更直接地提供了open方法,通过encoding参数传递字符编码名称,即可获得对 encoder和decoder的双向服务。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: