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还有很多不同的,这里先不说了,太晚了。

 

--------EOF---------
微信分享/微信扫码阅读