基本字符串操作
所有标准的序列操作(索引、分片、乘法、判断成员资格、求长度、取最小值和最大值)对字符串同样试用.但是字符串都是不可变的.
>>> web = 'http://www.python.org'
>>> web[-3:] = 'com'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
字符串格式化:精简版
字符串格式化使用字符串格式化操作符'%'来实现.
在百分号的左侧放置一个字符串(格式化字符串),而右侧放置希望格式化的值.可以使用一个值,如一个字符串或者数字,也可以使用多个值的元组或字典.
一般情况下使用元组:
>>> format = "hello %s %s enough for ya?"
>>> values = ('world', 'hot')
>>> print format % values
hello world hot enough for ya?
注意:如果使用序列代替元组,序列就会被解释为一个值.只有元组和字典可以格式化一个以上的值.
格式化字符串的'%s'部分是转换说明符,它们标记了需要插入转换值的位置.'s'表示值会被格式化为字符串——如果不是字符串,则会用 str 将其转换为字符串.
注意:如果想在格式化字符串里面包含百分号,那么必须使用'%%',这样 Python 就不会将百分号误认为时转换说明符了.
如果要格式化实数(浮点数),可以使用'f'说明符类型,同时提供所需的精度:一个句点再加上希望保留的小数位数.因为格式化说明符总是以表示类型的字符结束,所以精度应该放在类型字符前面:
>>> format = 'Pi with three decimals: %.3f'
>>> from math import pi
>>> print format % pi
Pi with three decimals: 3.142
模板字符串
string 模块提供另外一种格式化值的方法:模板字符串.如下所示,substitute 这个模板方法会用传递进来的关键字参数 foo 替换字符串中的 $foo:
>>> from string import Template
>>> s = Template('$x, glorious $x!')
>>> s.substitute(x='slurm')
'slurm, glorious slurm!'
>>> s
<string.Template object at 0x7fda1d611950>
如果替换字段是单词的一部分,那么参数名就必须用括号括起来,从而准确指明结尾:
>>> s = Template("It is ${x}tastic!")
>>> s.substitute(x='slurm')
'It is slurmtastic!'
可以使用 $$ 插入美元符号:
>>> s = Template("Make $$ selling $x!")
>>> s.substitute(x='slurm')
'Make $ selling slurm!'
除了关键字参数之外,还可以使用字典变量提供值/名称对(参见第四章):
>>> s = Template('A $thing must never $action.')
>>> d = {}
>>> d['thing'] = 'gentleman'
>>> d['action'] = 'show his socks'
>>> s.substitute(d)
'A gentleman must never show his socks.'
方法 safe_substitute 不会因缺少值或者不正确使用 $ 字符而除错.
字符串格式化:完整版
格式化操作符的右操作数可以是任何东西,如果是元组或者映射类型(如字典),那么字符串格式化将会有所不同.
如果右操作数是元组的话,则其中的每一个元素都会被单独格式化,每个值都需要一个对应的转换说明符.
注意:如果需要转换的元组作为转换表达式的一部分存在,那么必须将它用圆括号括起来.以避免出错.
>>> '%s plus %s equals %s' % (1, 1, 2)
'1 plus 1 equals 2'
>>> '%s plus %s equals %s' % 1, 1, 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: not enough arguments for format string
>>> '%s plus %s equals %s' % (1, 1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: not all arguments converted during string formatting
>>> '%s plus %s equals %s' % (1, 1,)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: not enough arguments for format string
基本的转换说明符包括以下部分.注意,这些项的顺序是至关重要的.
(1) % 字符:标记转换说明符的开始.
(2) 转换标志(可选):
- 表示左对齐
+ 表示在转换值之前要加上正负号
“” (空白字符)表示正数之前保留空格
0 表示转换值若位数不够则用 0 填充
(3) 最小字段宽度(可选):转换后的字符串至少应该具有该值指定的宽度.如果是 * ,则宽度会从值元组中读出.
(4) 点(.)后跟精度值(可选):
如果转换的是实数,精度值就表示出现在小数点后的位数.
如果转换的是字符串,那么该数字就表示最大字段宽度.
如果是 * ,那么精度将会从元组中读出.
(5) 转换类型:
表 3-1 字符串格式化转换类型
转换类型 含义
d, i 带符号的十进制整数
o 不带符号的八进制
u 不带符号的十进制
x 不带符号的十六进制(小写)
X 不带符号的十六进制(大写)
e 科学计数法表示的浮点数(小写)
E 科学计数法表示的浮点数(大写)
f, F 十进制浮点数
g 如果指数大于 -4 或者小于精度值则和 e 相同,其他情况与 f 相同
G 如果指数大于 -4 或者小于精度值则和 E 相同,其他情况与 F 相同
C 单字符(接受整数或者单字符字符串)
r 字符串(使用 repr 转换任意 Python 对象)
s 字符串(使用 str 转换任意 Python 对象)
简单转换
简单转换只需要写出转换类型:
>>> 'Price of eggs: $%d' % 42
'Price of eggs: $42'
>>> 'Hexadecimal price of eggs: %x' % 42
'Hexadecimal price of eggs: 2a'
>>> from math import pi
>>> 'Pi: %f...' % pi
'Pi: 3.141593...'
>>> 'Very inexact estimate of pi: %i' % pi
'Very inexact estimate of pi: 3'
>>> 'Using str: %s' % 42L
'Using str: 42'
>>> 'Using repr: %r' % 42L
'Using repr: 42L'
字符宽度和精度
转换说明符可以包括宽度和精度.字段宽度是转换后的值所保留的最小字符个数,精度(对于数字转换来说)则是结果中应该包含的小数位数,或者(对于字符串转换来说)是转换后的值所能包含的最大字符个数.
>>> '%10f' % pi # 字段宽 10
' 3.141593'
>>> '%10.2f' % pi # 字段宽 10, 精度 2
' 3.14'
>>> '%.2f' % pi # 精度 2
'3.14'
>>> '%.5s' % 'Guido van Rossum'
'Guido'
可以使用''(星号)作为字段宽度或者精度(或者两者都使用 ),此时数值会从元组参数中读出:
>>> '%.*s' % (5, 'Gudio van Rossum')
'Gudio'
>>> '%*.*s' % (2, 3, 123.1415926)
'123'
>>> '%*.*d' % (2, 3, 123.1415926)
'123'
>>> '%*.*f' % (2, 3, 123.1415926)
'123.142'
符号、对齐和 0 填充
在字段宽度和精度之前还可以放置一个"标表",该标表可以式零、加号、减号或空格.
# 0 表示将会用数字 0 进行填充
>>> '%010.2f' % pi
'0000003.14'
#减号(-)用来左对齐数值:
>>> '%-10.2f' % pi
'3.14 '
#空白意味着在整数前加上空格.这在需要对齐正负数时会很有用:
>>> print ('% 5d' % 10) + '\n' + ('%+5d' % -10)
10
-10
#加号(+)不管正负数都要输出符号:
>>> print ('%+5d' % 10) + '\n' + ('%+5d' % -10)
+10
-10
字符串方法
字符串方法要比列表的方法丰富的多,这是因为字符串从 string 模板中"继承"了很多方法.因为字符串的方法实在太多,这里只介绍一些特别有用的,其他的可参见附录 B.
但是字符串未死
尽管字符串方法完全来源于 string 模块,但是这个模块还包括一些不能作为字符串方法使用的常量和函数.maketrans 函数就是其中之一,后面会将它和 translate 方法一起介绍.下面是一些有用的字符串常量.
- string.digits: 包含数字 0-9 的字符串
- string.letters: 包含所有字母(大写或小写)的字符串
- string.lowercase: 包含所有小写字母的字符串
- string.printable: 包含所有可打印字符的字符串
- string.punctuation: 包含所有标点的字符串
- string.uppercase: 包含所有大写字母的字符串
字母字符串常量(例如 string.letters)与地区有关(也就是说,其具体值取决于 Python 所配置的语言).如果可以确定自己使用的是 ASCII,那么可以在变量中使用 ascii_ 前缀,例如:string.asciiletters那么可以在变量中使用 ascii 前缀,例如:string.ascii_letters(在 Python 3.0 中都这样使用,string.letters 和其相关的内容都会被移除).
find
find 方法可以在一个较长的字符串中查找字符串.它返回子串所在位置的最左端索引.如果没有找到则返回 -1
>>> 'with a moo-moo here.'.find('moo')
7
>>> title = "Monty Python os Flying Circus"
>>> title.find('Monty')
0
>>> title.find('Python')
6
>>> title.find('Flying')
16
>>> title.find('zizizi')
-1
这个方法还可以接受可选的起始点和结束点参数:
>>> subject = '$$$ Get rich now!!! $$$'
>>> subject.find('$$$')
0
>>> subject.find('$$$', 1) # 只提供一个起始点
20
>>> subject.find('!!!')
16
>>> subject.find('!!!', 0, 16) # 提供起始点和结束点
-1
注意,由起始和终止值指定的范围(第二和第三个参数)包含第一个索引,但不包含第二个索引.
附录 B:rfind, index, rindex, count, startwith, endswith.
join
join 方法是非常重要的字符串方法,它是 split 方法的逆方法,用来在队列中添加元素:
>>> seq = [1, 2, 3, 4, 5]
>>> sep = '+'
>>> sep.join(seq) # 连接数字列表
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: sequence item 0: expected string, int found
>>> seq = ['1', '2', '3', '4']
>>> sep.join(seq) # 连接字符串列表
'1+2+3+4'
>>> dirs = '', 'usr', 'bin', 'env'
>>> '/'.join(dirs)
'/usr/bin/env'
>>> print 'c:' + '\\'.join(dirs)
c:\usr\bin\env
可以看到,需要添加的队列元素都必须是字符串.
lower
lower 方法返回字符串的小写字母版.
>>> 'Trondheim Hammer Dance'.lower()
'trondheim hammer dance'
>>> name = 'Gumby'
>>> names = ['gumby', 'smith', 'jones']
>>> if name.lower() in names:
... print 'Found it!'
...
Found it!
附录 B: islower, capitalize, swapcase, title, istitle, upper, isupper.
标题转换
和 lower 方法相关的是 title 方法(参见附录 B),它会将字符串转换为标题——也就是所有单词的首字母大写,而其他字母小写.但是它使用的单词划分方法可能会得到并不自然的结果:
>>> "that's all folks".title()
"That'S All Folks"
再介绍另外一个 string 模块的 capwords 函数:
>>> import string
>>> string.capwords("that's all, folks")
"That's All, Folks"
string.capwords(s[, sep]): 使用 split 函数分割字符串 s (以 sep 为分隔符),使用 capitalize 函数将分割得到的各单词首字母大写,并且使用 join 函数以 sep 为分隔符将各单词连接起来.
当然,如果要得到正确首字母大写的标题(这要根据你的风格而定,可能要小写冠词、连词及 5 个字母以下的介词等),那么还是得自己把握.
replace
replace 方法返回某字符串的所有匹配项均被替代之后得到字符串.
>>> 'This is a test'.replace('is', 'eez')
'Theez eez a test'
附录 B: expandtabs
split
split 方法是一个非常重要的字符串方法,它是 join 的逆方法,用来将字符串分割成序列.
>>> '1+2+3+4+5'.split('+')
['1', '2', '3', '4', '5']
>>> '/usr/bin/env'.split('/')
['', 'usr', 'bin', 'env']
>>> 'Using the default'.split()
['Using', 'the', 'default']
注意,如果不提供任何分隔符,程序会把所有空格作为分隔符(空格,制表,换行符).
附录 B: rsplit, splitlines.
strip
strip 方法返回去除两侧(不包括内部)空格的字符串:
>>> ' internal whitespace is kept '.strip()
'internal whitespace is kept'
>>>
>>> names = ['gumby', 'smith', 'jones']
>>> name = ' gumby'
>>> if name in names:
... print 'found it'
...
>>> if name.strip() in names:
... print 'found it'
...
found it
也可以指定需要去除的字符,将他们列为参数即可:
>>> '***** Spam * for * everyone!!! ***'.strip('*!')
' Spam * for * everyone!!! '
>>> '***** Spam * for * everyone!!! ***'.strip(' *!')
'Spam * for * everyone'
这个方法只会去除两侧的字符,所以字符串中的星号没有被去掉.
附录 B: lstrip, rstrip.
translate
translate 方法和 replace 方法一样,可以替换字符串中国的某些部分,但是 translate 方法只处理单个字符.它的优势在于可以同时进行多个替换,有时候比 replace 效率高得多.
在使用 translate 转换之前,需要先完成一张转换表.转换表中是以某字符替换某字符的对应关系.因为这个表(事实上是字符串)有多达 256 个项目,我们可以使用 string 模块里面的 maketrans 函数就行.
maketrans 函数接受两个参数:两个等长的字符串,表示第一个字符串中的每个字符都用第二个字符串中相同位置的字符替换.
>>> from string import maketrans
>>> table = maketrans('cs', 'kz')
# 转换表是包含替换 ASCII 字符集中256个字符的替换字母的字符串.
>>> len(table)
256
>>> table[97:123]
'abkdefghijklmnopqrztuvwxyz'
>>> maketrans('', '')[97:123]
'abcdefghijklmnopqrstuvwxyz'
>>>
>>> 'this is an incredible test'.translate(table)
'thiz iz an inkredible tezt'
translate 的第二个参数是可选的,这个参数是用来制定需要删除的字符.例如,如果想要模拟一句语速超快的德国语,可以删除所有空格:
>>> 'this is an incredible test'.translate(table, ' ')
'thizizaninkredibletezt'