1、Unicode编码
Unicode编码系统为表达任意语言的任意字符设计,使用4字节存储,每个数字代表唯一的至少在某种语言中使用的字符。被几种语言共用的字符通常使用相同的数字编码,除非存在一个在理的语源学理由不允许这样做。
Unicode编码模式有:
(1)、UTF-32:4字节存储,第N个字符从第4×Nth个字节开始。
(2)、UTF-16:2字节存储,将0-65535范围内的字符编码成2个字节,超过的需要一些技巧来实现。
使用UTF-32和UTF-16需要定义一个“字节顺序标记”,它是一个特殊的非打印字符,可以把它包含在文档的开头来指示你所使用的字节顺序。比如UTF-16,字节顺序标记为U+FEFF,如果收到的是FFFE开头的UTF-16编码文件,则字节顺序是单向的,以FEFF开头,则确定字节顺序反向了。
(3)、UTF-8:变长编码系统。对于ASCII仅用1字节,每个字符使用不同数量的字节编码。由于位操作的天性使然,使用UTF-8不再存在字节顺序的问题。一份以UTF-8编码的文档在不同的计算机之间是一样的比特流。
2、概述
在Python 3,所有的字符串都是使用Unicode编码的字符序列。不再存在以UTF-8或者CP-1252编码的情况。也就是说,“这个字符串是以utf-8编码的吗?不再是一个有效问题。”utf-8是一种将字符编码成字节序列的方式。如果需要将字符串转换成特定编码的字节序列,Python 3可以为你做到。如果需要将一个字节序列转换成字符串,Python 3也能为你做到。字节即字节,并非字符。字符在计算机内只是一种抽象。字符串则是一种抽象的序列。
>>> s = '深入 Python' ①
>>> len(s) ②
9
>>> s[0] ③
'深'
>>> s + ' 3' ④
'深入 Python 3'
上面的s中汉字也是算一个字符。
3、格式化字符串
>>> username = 'mark'
>>> password = 'PapayaWhip' ①
>>> "{0}'s password is {1}".format(username, password) ②
"mark's password is PapayaWhip"
① 不,PapayaWhip真的不是我的密码。
② 这里包含了很多知识。首先,这里使用了一个字符串字面值的方法调用。字符串也是对象,对象则有其方法。其次,整个表达式返回一个字符串。最后,{0}和{1} 叫做替换字段(replacement field),他们会被传递给format()方法的参数替换。
复合字段名:
>>> import humansize
>>> si_suffixes = humansize.SUFFIXES[1000] ①
>>> si_suffixes
['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
>>> '1000{0[0]} = 1{0[1]}'.format(si_suffixes) ②
'1000KB = 1MB'
在这里{0}代表传给format()的第一个字符,{1}代表传给format()的第二个字符。有效复合字段名:
- 使用列表作为参数,并且通过下标索引来访问其元素(跟上一例类似)
- 使用字典作为参数,并且通过键来访问其值
- 使用模块作为参数,并且通过名字来访问其变量及函数
- 使用类的实例作为参数,并且通过名字来访问其方法和属性
- 以上方法的任意组合
>>> import humansize
>>> import sys
>>> '1MB = 1000{0.modules[humansize].SUFFIXES[1000][0]}'.format(sys)
'1MB = 1000KB'
sys模块保存了当前正在运行的python实例的消息。
ys.modules
是一个保存当前Python实例中所有已经导入模块的字典。模块的名字作为字典的键;模块自身则是键所对应的值。在实际的Python代码中,字典sys.modules
的键是字符串类型的;为了引用它们,我们需要在模块名周围放上引号(比如 'humansize'
)。但是在使用替换域的时候,我们在省略了字典的键名周围的引号(比如 humansize
)。在此,我们引用PEP 3101:字符串格式化高级用法,“解析键名的规则非常简单。如果名字以数字开头,则它被当作数字使用,其他情况则被认为是字符串。”
>>> '{0:.1f} {1}'.format(698.24, 'GB') '698.2 GB'这里:表示格式说明符的开始,.1表示四舍五入到小数点后1位,f表示浮点数。
4、其他字符串常用方法
>>> s = '''Finished files are the re- ①
... sult of years of scientif-
... ic study combined with the
... experience of years.'''
>>> s.splitlines() ②
['Finished files are the re-',
'sult of years of scientif-',
'ic study combined with the',
'experience of years.']
>>> print(s.lower()) ③
finished files are the re-
sult of years of scientif-
ic study combined with the
experience of years.
>>> s.lower().count('f') ④
6
>>> query = 'user=pilgrim&database=master&password=PapayaWhip'
>>> a_list = query.split('&') ①
>>> a_list
['user=pilgrim', 'database=master', 'password=PapayaWhip']
>>> a_list_of_lists = [v.split('=', 1) for v in a_list] ②
>>> a_list_of_lists
[['user', 'pilgrim'], ['database', 'master'], ['password', 'PapayaWhip']]
>>> a_dict = dict(a_list_of_lists) ③
>>> a_dict
{'password': 'PapayaWhip', 'user': 'pilgrim', 'database': 'master'}
字符串的分片:
>>> a_string = 'My alphabet starts where your alphabet ends.'
>>> a_string[3:11] ①
'alphabet'
>>> a_string[3:-3] ②
'alphabet starts where your alphabet en'
>>> a_string[0:2] ③
'My'
>>> a_string[:18] ④
'My alphabet starts'
>>> a_string[18:] ⑤
' where your alphabet ends.'
5、STRING vs. BYTES
字节即字节;字符是一种抽象。一个不可变(immutable)的Unicode编码的字符序列叫做string。一串由0到255之间的数字组成的序列叫做bytes对象。
>>> by = b'abcd\x65' ①
>>> by
b'abcde'
>>> type(by) ②
<class 'bytes'>
>>> len(by) ③
5
>>> by += b'\xff' ④
>>> by
b'abcde\xff'
>>> len(by) ⑤
6
>>> by[0] ⑥
97
>>> by[0] = 102 ⑦
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'bytes' object does not support item assignment
① 使用“byte字面值”语法b''来定义bytes对象。byte字面值里的每个字节可以是ascii字符或者是从\x00到\xff编码了的16进制数。
② bytes对象的类型是bytes。
③ 跟列表和字符串一样,我们可以通过内置函数len()来获得bytes对象的长度。
④ 使用+操作符可以连接bytes对象。操作的结果是一个新的bytes对象。
⑤ 连接5个字节的和1个字节的bytes对象会返回一个6字节的bytes对象。
⑥ 一如列表和字符串,可以使用下标记号来获取bytes对象中的单个字节。对字符串做这种操作获得的元素仍为字符串,而对bytes对象做这种操作的返回值则为整数。确切地说,是0–255之间的整数。
⑦ bytes对象是不可变的;我们不可以给单个字节赋上新值。如果需要改变某个字节,可以组合使用字符串的切片和连接操作(效果跟字符串是一样的),或者我们也可以将bytes对象转换为bytearray对象。
>>> by = b'abcd\x65'
>>> barr = bytearray(by) ①
>>> barr
bytearray(b'abcde')
>>> len(barr) ②
5
>>> barr[0] = 102 ③
>>> barr
bytearray(b'fbcde')
① 使用内置函数bytearray()来完成从bytes对象到可变的bytearray对象的转换。
② 所有对bytes对象的操作也可以用在bytearray对象上。
③ 有一点不同的就是,我们可以使用下标标记给bytearray对象的某个字节赋值。并且,这个值必须是0–255之间的一个整数。
决不能混用strings和bytes
>>> by = b'd'
>>> s = 'abcde'
>>> by + s ①
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't concat bytes to str
>>> s.count(by) ②
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't convert 'bytes' object to str implicitly
>>> s.count(by.decode('ascii')) ③
1
① 不能连接bytes对象和字符串。他们两种不同的数据类型。
② 也不允许针对字符串中bytes对象的出现次数进行计数,因为串里面根本没有bytes。字符串是一系列的字符序列。也许你是想要先把这些字节序列通过某种编码方式进行解码获得字符串,然后对该字符串进行计数?可以,但是需要显式地指明它。Python 3不会隐含地将bytes转换成字符串,或者进行相反的操作。
③ 好巧啊…这一行代码刚好给我们演示了使用特定编码方式将bytes对象转换成字符串后该串的出现次数。
所以,这就是字符串与字节数组之间的联系了:bytes对象有一个decode()方法,它使用某种字符编码作为参数,然后依照这种编码方式将bytes对象转换为字符串,对应地,字符串有一个encode()方法,它也使用某种字符编码作为参数,然后依照它将串转换为bytes对象
>>> a_string = '深入 Python' ①
>>> len(a_string)
9
>>> by = a_string.encode('utf-8') ②
>>> by
b'\xe6\xb7\xb1\xe5\x85\xa5 Python'
>>> len(by)
13
>>> by = a_string.encode('gb18030') ③
>>> by
b'\xc9\xee\xc8\xeb Python'
>>> len(by)
11
>>> by = a_string.encode('big5') ④
>>> by
b'\xb2`\xa4J Python'
>>> len(by)
11
>>> roundtrip = by.decode('big5') ⑤
>>> roundtrip
'深入 Python'
>>> a_string == roundtrip
True
① a_string是一个字符串。它有9个字符。
② by是一个bytes对象。它有13个字节。它是通过a_string使用utf-8编码而得到的一串字节序列。
③ by还是一个bytes对象。它有11个字节。它是通过a_string使用GB18030编码而得到的一串字节序列。
④ 此时的by仍旧是一个bytes对象,由11个字节组成。它又是一种完全不同的字节序列,我们通过对a_string使用Big5编码得到。
⑤ roundtrip是一个字符串,共有9个字符。它是通过对by使用Big5解码算法得到的一个字符序列。并且,从执行结果可以看出,roundtrip与a_string是完全一样的。
6、可以指定python源码的编码方式
Python3默认采用UTF-8编码,而Python2采用ASCII
可以每个文件的第一行
# -*- coding: windows-1252 -*-
或者
#!/usr/bin/python3
# -*- coding: windows-1252 -*-