python的字符串
今天读了一下《Python高级编程》里的字符串与Unicode一章,深入研究一下,还真是发现了很多的问题。现在就把比较重要的点记录下来。
如果说Py2和Py3有什么不同,我觉得字符串的处理机制是两者之间比较重要的不同之一,也可以说是Py3做的比较好的优化之处。
在python中有两种类型的字符串:文本字符串和字节字符串。首先要弄清楚这两者的区别,然后在说在两个版本python中的不同。
文本字符串:很直白,就是我们文本数据中的一系列的字符的组合。
字节字符串:虽然展示给我们的是这些文本字符串,但最终这些数据是需要存储在计算机或者传输的,计算机可不认你写的文本字符串,计算机只认识二进制,即一大堆1和0,因此这就衍生出了编解码,要将数据进行存储,就需要将文本字符串进行相应的编码成对应字节。
最早的是美国的ASCII标准,它是用一个字节对应一个字符,一共就127个,就是你键盘上能够看到的。这也就解释了为什么在python2中,如果不在文本开头添加utf-8等其他编码方式,当你有中文进行解码时,就会报ascii UnicodeDecodeError错误。后来为了扩展,又出现了LATIN-1,GBK等等,但这终究是参差不齐,为了统一,后来出现了UNICODE字符集,它几乎包含了世界所有用到的字符,对应的出现了各种编码方式,utf-8,utf-16,utf-32。也就是说你要分清UNICODE字符集和utf-8,utf-16之类的说的不是一回事。前者表示整个字符集,后者表示编码方式。而这几种编码方式也有不同:
- utf-16 表示用2个字节编码字符;有时2个字节不够;
- utf-32 表示用4个字节编码字符;非常容易造成浪费;
- utf-8 可变长字节编码方式。由于字节可根据字符变化,因为应用最广泛;
OK,弄清了上面的概念,我们就来说说在Python中的应用。由于Python3更便捷,更方面,所以我先说python3.
一、Python3
python3一个最大的特点就是字符串都是UNICODE类型,默认编码方式是UTF-8。
所有文本字符串都是用str表示,字节字符串用bytes表示。
>>> s='abc'
>>> a=b'abc'
>>> type(s),type(a)
(<class 'str'>, <class 'bytes'>)
我们可以将文本字符串转换为字节:
>>> s='abc'
<class 'str'>
>>> s.encode('utf-8')
b'abc'
>>> bytes(s,'utf-8')
b'abc'
同样,可以将字节字符串解码成文本字符串:
>>> d
b'abc'
>>> d.decode('utf-8')
'abc'
>>> d
b'abc'
>>> str(d,'utf-8')
'abc'
这里再说一点啊,字节字符串只是为了让我们方便阅读,实际上,每个字符都已经编成二进制了,如:
>>> S.encode('ascii') # Values 0..127 in 1 byte (7 bits) each
b'XYZ'
>>> S.encode('latin-1') # Values 0..255 in 1 byte (8 bits) each
b'XYZ'
>>> S.encode('utf-8') # Values 0..127 in 1 byte, 128..2047 in 2, others 3 or 4
b'XYZ'
比如现在我们对字节数据进行序列操作:
>>> s
b'abcde'
>>> s[0]
97
>>> s[1]
98
对字节字符串进行序列操作,看上面的结果,获得的是对应的二进制数据。即ord('a')=97
这也就意味着你不可以将字节字符串和文本字符串进行连接操作:
>>> s
b'abcde'
>>> a='w'
>>> s+a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't concat bytes to str
这点和在python2中是完全不同的,后面我会再说。其实说实话,在python3中,分得更明显,更方便。
二、Python2
相对Py3,Python2可能有点混乱。
str用来表示字节字符串和8位的文本字符串;unicode表示Unicode文本;
c='s'
#文本字符串
print 'c:',type(c)
s=u'海波'
print 's:',type(s)
#字节字符串
print 'bytes(c):',type(bytes(c))
#字节字符串
a=s.encode('utf-8')
print 'encode utf8:',type(a)
c: <type 'str'>
s: <type 'unicode'>
bytes(c): <type 'str'>
encode utf8: <type 'str'>
看上面的结果,str既表示了文本字符串,也表示了8位的文本;
好,现在我对py2中的文本字符串和字节字符串进行连接操作:
c='s'.encode('utf-8')
a=u'海波'
print c+a,type(c+a)
输出:s海波 <type 'unicode'>
这个和python3就很不同了,字节字符串和unicode文本字符串相加,变成了文本字符串,有点像C语言中的类型隐士转换。
为了能让在python2中的代码以后能在python3中得到兼容,python2中有一个__future__模块,可以引入python3中的语法。比如下面这个例子:
#coding:utf-8
from __future__ import unicode_literals
import sys
import datetime
a= u'%m月%d日'.encode('utf-8')
reload(sys)
sys.setdefaultencoding('utf-8')
print datetime.datetime.now().strftime('%m月%d日')
print '海波'
上面说这个例子除了要说如何在py2中使用py3的语法,还要说明一下下面的例子,我也是看the5fire(嗯,我从这个哥们那学到很多)那看到的。strftime接收的是字节字符串,当我们给它传递一个文本字符串的时候,它会使用默认的编码方式将文本字符串转换为字节字符串。假如我们使用python2默认的ASCII编码,那上面的就会报错:UnicodeEncodeError: 'ascii' codec can't encode character u'\u6708' in position 2: ordinal not in range(128)。
这是必然的,因为我们上面有中文字符月和日。所以我在上面重载了python的编码方式。其实还有一种方法:就是显示地传入字节字符串,在python3中就是bytes类型。
好了,暂时先说这么多。其实在读写文本时,py2和py3还有很多不同的,这里先不说了,太晚了。
微信分享/微信扫码阅读