开篇

上一期介绍了字符串及其切片用法,相信你已经掌握。

那么这一期,我们就来学习一下字符串的增删改查等一系列方法,正是因为有了这些方法,你才能像呼吸一样自然地操作字符串。

需要指出的是,字符串是不可变类型,也就是说,只要一个字符串确定了,那么任何操作都不能修改该字符串。

此时的你,可能会很疑惑:既然字符串是不可变类型,那何来增删改这些操作呢?

解答这个问题的过程涉及到了内存,下面我将用画图的方式解释:

将内存看作一个大房子,房子中有许多小房间(地址单元),将它们分别编号为0123

img

在运行s='great'这一句代码时,会给变量s分配一个房间,假设分配的房间号是0

img

现在,我想要修改变量s中的内容,由great改成gre!。由于字符串是不可变数据类型,所以不能直接在变量s所在的小房间(地址单元)内进行修改。

正确的做法是新开一个小房间,假如新开的小房间是1号,则首先会将s的前3个字符复制到房间1(这里用到了切片,你还记得吗),然后在后面加一个!。这样,房间1内所保存的就是我们想要的结果了。

以上文字描述过程对应代码如下:

1
2
3
4
>>> s='great'
>>> new=s[0:3]+'!'# +用于拼接两个字符串,本期马上就讲到
>>> print(new)
gre!

img

看,原来的字符串变量s和修改后的字符串变量new在两个不同的房间。可以肯定的是,字符串不可不变类型,是不会变的;修改后的结果保存在了新的地址单元内。

Python中提供了id()函数,用于查看两个内存中的地址单元是否是同一个(这里,你就理解为查看两个小房间的房间号是不是同一个):

1
2
3
4
>>> id(s)
2121690232688
>>> id(new)
2121689684592

结果很明显了,房间号完全不一样!

总结来说:当对字符串执行增删改等操作时,最终的结果会保存到一个新的内存地址单元内(这里就是指小房间1),而原来的内存地址单元(这里指的是小房间0)所保存的东西是不会发生任何改变的。

此时,可能又会有人问:如果代码改成这个样子呢?

1
2
3
4
>>> s='great'
>>> s=s[0:3]+'!'
>>> print(s)
gre!

你看吧,s变了!我只要将修改后的字符串的名字也用s表示,字符串就变了呀!

:非也。你把变量变量所保存的内容搞混了。还记得变量那节的知识吗?变量是可以变化的,所以你这里将新的字符串也用原来的变量名来表示这一操作,实际上修改的是变量中的内容,原来的字符串中的内容被新的内容”抹去”了你可以抹去我的存在,但我初心不改—by 字符串。想起来了吧~

好,说了这么多,终于可以开始今天的主要内容了。上面的内容对于零基础的同学来说,如果很难理解也没关系,只要记住字符串是不可变的,继续往下看即可。待到时机成熟,自然就理解了。

接下来的内容,都是一些记忆性的东西,以后用到时再来查也可以。

不过,强烈建议初学者跟着敲一遍,能记多少记多少,这样可以加深印象,培养写代码的手感,也有助于后续内容的学习。

字符串中常用的查找操作

1.find()

查找字符串中某个字符串首次出现的下标,不存在则返回-1

1
2
3
4
5
6
7
>>> s='abcdabcd'
>>> s.find('c')
2
>>> s.find('abc')
0
>>> s.find('abcdd')
-1

上面的查找方式是默认从下标为0处开始查找的,我们也可以手动修改从哪个下标处开始查找,只需要再传入一个下标即可:

1
2
3
4
5
>>> s='abcdabcd'
>>> s.find('a',2)#从下标为2的地方开始查找'a'
4
>>> s.find('abcd',1)#从下标为1的地方开始查找'abcd'
4

也可以同时指定查找的开始下标和结束下标:

1
2
3
4
5
6
7
8
9
>>> s='abcdabcd'
>>> s.find('a',1,6)
4
>>> s.find('a',-6,-1)
4
>>> s.find('a',1,8)#即使越界也不报错
4
>>> s.find('a',1,2333)#即使越界也不报错
4

2.index()

find()功能用法几乎一模一样,只是index()在查找失败时会报错,而find()返回-1

1
2
3
4
5
6
7
8
9
10
11
12
>>> s='abcdabcd'
>>> s.index('a')
0
>>> s.index('a',1)#指定查找开始位置
4
>>> s.index('a',1,5)#指定查找开始位置和结束位置
4
>>> s.index('abce')#找不到就报错

Traceback (most recent call last):
File "<pyshell#45>", line 1, in <module>
s.index('abce')ValueError: substring not found

3.rfind()

find()一样,只是rfind()是从后面往前面查(从下标大的位置开始,往下标小的位置扫描)

1
2
3
4
5
6
7
8
9
10
11
>>> s='abcdabcd'
>>> s.rfind('d')
7
>>> s.rfind('d',2)#指定开始位置,这里是2,就说明查找范围是从2一直到最后的len(s)-1,只不过是从后向前查
7
>>> s.rfind('d',2,6)#指定开始和结束位置,也就是查找区间
3
>>> s.rfind('d',6,2)#指定开始和结束位置,也就是查找区间,但由于start>end,因此区间为空,自然也就找不到'd'了
-1
>>> s.rfind('d',-2,-5)#同上
-1

4.rindex()

index()一样,只是从后往前查询,并且找不到就报错

1
2
3
4
5
6
7
8
9
10
>>> s='abcdabcd'
>>> s.rindex('b')
5
>>> s.rindex('b',5)
5
>>> s.rindex('b',1,7)
5
>>> s.rindex('abce')#找不到就报错

Traceback (most recent call last): File "<pyshell#70>", line 1, in <module> s.rindex('abce')ValueError: substring not found>>> s.rindex('cba')#找不到就报错Traceback (most recent call last): File "<pyshell#71>", line 1, in <module> s.rindex('cba')ValueError: substring not found

字符串中的替换操作

使用replace()

replace('old str','new str')用于将字符串中的old str替换成new str

1
2
3
>>> word='fantastic'
>>> word.replace('a','A')
'fAntAstic'

也可以指定最大替换次数

1
2
3
>>> word='fantastic'
>>> word.replace('a','A',1)
'fAntastic'

这里指定的最大替换次数为1,因此只把第一个出现的a替换成了A

字符串的拼接

使用+即可将若干字符串拼接成一个大的字符串。

1
2
3
4
5
6
>>> s1='1!'
>>> s2='2'
>>> s3='3'
>>> s=s1+s2+s3
>>> print(s)
123

字符串中常用的分割操作

分割操作,指的是把一个字符串分割成几个小的部分。

【注意】这里可能会出现列表,元组,我们还没有讲到。不过相信我,它们并不影响本节的阅读。

1.split()

()里面填写分隔符,如果没有填写任何字符的话,则使用默认值(空格)``。

1
2
3
4
5
>>> s='a-b-c-d'
>>> s.split()#没有填写的话,默认使用空格分割,所以分不开
['a-b-c-d']
>>> s.split('-')#此时传入了分隔符'-',所以分割开了
['a', 'b', 'c', 'd']

我们也可以指定分割的次数,见下栗:

1
2
3
>>> s='a-b-c-d'
>>> s.split('-',2)#分割次数为2
['a', 'b', 'c-d']

2.rsplit()

从后往前分割,只有在指定分割次数时才能看得见效果,其余结果和split()是一样的

1
2
3
4
5
6
7
8
9
>>> s='a-b-c-d'
>>> s.rsplit()#和`split()`结果一样
['a-b-c-d']

>>> s.rsplit('-')#和`split()`结果一样
['a', 'b', 'c', 'd']

>>> s.rsplit('-',2)#指定了最大分割次数为2,所以第一个'-'没有被处理
['a-b', 'c', 'd']

3.partition

将字符串分割为3个部分,可用于分割一个文件的文件名和后缀名,直接上栗子

1
2
3
4
5
6
>>> file_name='xxx.py'
>>> x=file_name.partition('.')#按照'.'来分割
>>> x[2]#查看后缀名
'py'
>>> x[0]#查看文件名
'xxx'

但是,如果我的文件名和后缀名是这个样子的:xxx.yy.py,上面的做法就会有问题:

1
2
3
4
5
6
>>> new_file_name='xxx.yy.py'
>>> x=new_file_name.partition('.')
>>> x[2]
'yy.py'
>>> x[0]
'xxx'

看,文件名本来是xxx.yy,而分割而来的文件名是xxx,同样后缀名也出错了。

这是因为,partition()是从左往右扫描的,扫描到第一个()内指定的分隔符(这里就’.’)就开始分割,分割符自己作为一部分,其左右两侧的字符串各作为一部分,总共3部分。

那也没有解决办法呢?简单,只需要将扫描的顺序改为从右向左就好了。下面的rpartition()就做了这件事。

4.rpartition()

来直接看栗子:

1
2
3
4
5
6
7
8
>>> new_file_name='xxx.yy.py'
>>> x=new_file_name.rpartition('.')#x共3部分
>>> x[0]'
xxx.yy'
>>> x[2]
'py'
>>> x[1]
'.'

x[0]取出的便是文件名,x[2]取出的是后缀名。

字符串的格式化操作

1.ljust()

让字符串以指定长度显示,如果长度不够,则在右边填充。默认使用空格填充,可手动修改,看栗子

1
2
3
4
5
>>> x='Good'
>>> x.ljust(6)#默认以空格填充
'Good '
>>> x.ljust(6,'*')#以'*'填充
'Good**'

如果指定的长度小于原字符串本身的长度,则返回原字符串

1
2
3
>>> x='Good'
>>> x.ljust(3)#3<4
'Good'

2.rjust

ljust功能相同,只不过是在左边进行填充

1
2
3
4
5
6
7
>>> x='Good'
>>> x.rjust(6)#在左边默认以空格填充
' Good'
>>> x.rjust(6,'*')#在左边以'*'填充'
**Good'
>>> x.rjust(3) #3<4
'Good'

3.center

功能同上,只是在两侧填充

1
2
3
4
5
6
7
>>> x='Good'
>>> x.center(6,'*')
'*Good*'
>>> x.center(7,'*')
'**Good*'
>>> x.center(8,'*')
'**Good**'

这里推荐一个记忆的方法:

ljust中的l代表left,意思是说让原字符串左对齐,所以是在右边填充;

rjust中的r代表right,意思是说让原字符串右对齐,所以是在左边填充;

center代表中间,意思是说让原字符串居中,所以是在字符串两侧填充;

删除字符串中的特定内容

1.strip()

注意:这个方法只能删除字符串开头或结尾的字符,不能删除中间部分的字符
如果()内什么也不写,默认就是删除字符串中的空格

1
2
3
4
5
6
>>> x='  ab c d    '
>>> x.strip()#默认删除空格
'ab c d'
>>> s='**abc*d**'#指定删除字符为'*'
>>> s.strip('*')
'abc*d'

2.rstrip()

看完了上面的内容,这里已经不必多讲了吧,直接上栗子:

1
2
3
4
5
6
>>> x='  ab c d    '#删除右边的空格
>>> x.rstrip()
' ab c d'
>>> s='**abc*d**'
>>> s.rstrip('*')#删除右边的指定字符
'**abc*d'

3.lstrip()

同样直接上栗子!

1
2
3
4
5
6
>>> x='  ab c d    '
>>> x.lstrip()
'ab c d '
>>> s='**abc*d**'
>>> s.lstrip('*')
'abc*d**'

字符串中的大小写转换方法

1.upper()

将字符串中的所有字符全部变成大写

1
2
3
>>> s='abcDEFg'
>>> s.upper()
'ABCDEFG'

2.lower()

将字符串中的所有字符全部变成小写

1
2
3
>>> s='abcDEFg'
>>> s.lower()
'abcdefg'

3.swapcase()

大写变小写,小写变大写

1
2
3
>>> s='abcDEFg'
>>> s.swapcase()
'ABCdefG'

4.title

让每个单词的首字母大写

1
2
3
>>> seq='hello world I Love Python'
>>> seq.title()'
Hello World I Love Python'

5.capitalize()

只让字符串的首字母大写,其余部分均小写

1
2
3
>>> seq='hello world I Love Python'
>>> seq.capitalize()
'Hello world i love python'