6.3 字符串和操作符

6.3.1 标准类型操作符

在第4章里面,我们介绍了一些适用于包括标准类型在内的大部分对象的操作符,在这里再看一下其中的一些操作符是怎样作用于字符串类型的,下面是几个简单的例子。

6.3 字符串和操作符 - 图1

在做比较操作的时候,字符串是按照ASCII值的大小来比较的。

6.3.2 序列操作符切片([]和[:])

在先前的6.1.1节里面我们展示了如何访问序列类型的一个或一组元素,接下来我们会把这些知识应用到字符串类型上,着重考察以下的操作;

  • 正向索引;

  • 反向索引;

  • 默认索引。

接下来以字符串‘abcd’为例子。表里面分别列出了使用正索引和负索引来定位字符的情况。可以用长度操作符来确认该字符串的长度是4。

6.3 字符串和操作符 - 图2

6.3 字符串和操作符 - 图3

正向索引时,索引值开始于0,结束于总长度减1(因为我们是从0开始索引的)。本例中最后一个索引是:

6.3 字符串和操作符 - 图4

在这个范围内,我们可以访问任意的子串。用一个参数来调用切片操作符结果是一个单一字符,而使用一个数值范围(用)作为参数调用切片操作的参数会返回一串连续地字符。再强调一遍,对任何范围[start:end],我们可以访问到包括start在内到end(不包括end)的所有字符,换句话说,假设x是[start:end]中的一个索引值,那么有:start<=x<end。

6.3 字符串和操作符 - 图5

使用不在允许范围(本例中是0到3)内的索引值会导致错误。上面的aString[2:4]却并没有出错,那是因为实际上它返回的是索引值2和3的值。但是直接拿4作为索引访问是不被允许的。

在进行反向索引操作时,是从-1开始,向字符串的开始方向计数,到字符串长度的负数为索引的结束。最末一个索引(也就是第一个字符)是这样定位的:

6.3 字符串和操作符 - 图6

如果开始索引或者结束索引没有被指定,则分别以字符串的第一个和最后一个索引值为默认值。

6.3 字符串和操作符 - 图7

注意:起始/结束索引都没有指定的话会返回整个字符串。

1. 成员操作符(in,not in)

成员操作符用于判断一个字符或者一个子串(中的字符)是否出现在另一个字符串中。出现则返回True,否则返回False。注意,成员操作符不是用来判断一个字符串是否包含另一个字符串的,这样的功能由find()或者index()(还有它们的兄弟:rfind()和rindex())函数来完成。

下面是一些字符串和成员操作符的例子。在Python 2.3以前,in(和not in)操作符只允许用来判断一个单个字符是否属于一个字符串,就像下面第2个例子那样。2.3以后这个限制去掉了,所有的字符串都可以拿来判断。

6.3 字符串和操作符 - 图8

在例6.1里面,我们会用到下面这些string模块预定义的字符串:

6.3 字符串和操作符 - 图9

例6.1是一个用来检查Python有效标识符的小脚本,名字是idcheck.py。我们知道,Python标识符必须以字母或下划线开头,后面跟字母、下划线或者数字。

例6.1 标识符检查(idcheck.py)

标识符合法性检查,首先要以字母或者下划线开始,后面要跟字母,下划线或者或数字。这个小例子只检查长度大于等于2的标识符。

6.3 字符串和操作符 - 图10

这个例子还展示了字符串连接符(+)的使用,本章的后面会讲到字符串连接符。运行几次后得到下面的输出:

6.3 字符串和操作符 - 图11

6.3 字符串和操作符 - 图12

让我们逐行解释这个应用程序。

3 ~ 6行

导入string模块并且预定义了两个字符串,用于后面的判断。

8 ~ 12行

输出提示信息,第12行的if语句过滤掉长度小于2的标识符或者候选标识符。

14 ~ 16行

检查第一个符号是不是字母或下划线,如果不是,输出结果并退出。

17 ~ 18行

否则,从第二个字符开始到最后一个字符,循环检查剩余的字符。

20 ~ 23行

检查剩余的符号是否都是字母,下划线或者数字。注意我们是如何使用连接操作符来创建合法字符集合的。只要发现一个非法字符,就显示结果并通过break语句退出。

6.3 字符串和操作符 - 图13核心提示:性能

6.3 字符串和操作符 - 图14

24 ~ 25行

或许现在就向你展示for-else循环语句有点儿早,可是我们必须先看一看这个语句(在第8章有详细的介绍)。for循环的else语句是一个可选项,它只在for循环完整的结束,没有遇到break时执行。在我们的例子中,如果所有的符号都检查合格,那么我们就得到了一个合法的标识符,程序会返回一个这样的结果,然后执行完毕。

其实,这段程序并不是完美的,一个问题就是标识符的长度必须大于1。我们的程序几乎是,但还并没有真正定义出Python标识符的范围,Python标识符长度可以是1。另一个问题是这段程序并没有考虑到Python的关键字,而这些都是作为保留字,不允许用做标识符的。我们把这两个问题作为课后练习留给读者(见练习6-2)。

2. 连接符(+)

运行时刻字符串连接

我们可以通过连接操作符来从原有字符串获得一个新的字符串。我们已经在前面的例6-1里面见识过连接符了,下面是一些更多的例子:

6.3 字符串和操作符 - 图15

最后一个例子展示了用一个字符串s的两个切片来构成一个新串的操作,从“Spanish”里面切出“Spa”加上从“Made”里面切出来的“M”。将抽取出来字符串切片连接后作为参数传给了string.upper()方法,该方法负责把字符串的所有字符都变为大写。String模块的方法是在Pythonl.6里面添加进来的,所以这个操作也可以用最后一个字符串的一个单一方法调用来完成(见下面的例子)。现在已经没有必要导入string模块了,除非你需要访问该模块自己定义的字符串常量。注意:虽然对初学者来说string模块的方式更便于理解,但出于性能方面的考虑,我们还是建议你不要用string模块。原因是Python必须为每一个参加连接操作的字符串分配新的内存,包括新产生的字符串。取而代之,我们推荐你像下面介绍的那样使用字符串格式化操作符(%),或者把所有的字符串放到一个列表中去,然后用一个join()方法来把它们连接在一起。

6.3 字符串和操作符 - 图16

3. 编译时字符串连接

上面的语法在运行时字符串连接的加法操作,这个用法是非常标准的。Python中还有一种并不是经常用到,更像是一种程序员的习惯用法的语法。Python的语法允许你在源码中把几个字符串连在一起写,以此来构建新字符串。

6.3 字符串和操作符 - 图17

通过这种方法,你可以把长的字符串分成几部分来写,而不用加反斜杠。如上所示,你可以在一行里面混用两种分号。这种写法的好处是你可以把注释也加进来,如下所示。

6.3 字符串和操作符 - 图18

如你所想,下面就是urlopen()方法所得到的真实输入。

6.3 字符串和操作符 - 图19

4. 普通字符串转化为Unicode字符串

如果把一个普通字符串和一个Unicode字符串做连接处理,Python会在连接操作前先把普通字符串转化为Unicode字符串:

6.3 字符串和操作符 - 图20

重复操作符创建一个包含了原有字符串的多个拷贝的新串。

6.3 字符串和操作符 - 图21

像其他的标准操作符一样,原变量是不被修改的,就像上面最后一个例子所示。