6.3 字符串和操作符
6.3.1 标准类型操作符
在第4章里面,我们介绍了一些适用于包括标准类型在内的大部分对象的操作符,在这里再看一下其中的一些操作符是怎样作用于字符串类型的,下面是几个简单的例子。
在做比较操作的时候,字符串是按照ASCII值的大小来比较的。
6.3.2 序列操作符切片([]和[:])
在先前的6.1.1节里面我们展示了如何访问序列类型的一个或一组元素,接下来我们会把这些知识应用到字符串类型上,着重考察以下的操作;
正向索引;
反向索引;
默认索引。
接下来以字符串‘abcd’为例子。表里面分别列出了使用正索引和负索引来定位字符的情况。可以用长度操作符来确认该字符串的长度是4。
正向索引时,索引值开始于0,结束于总长度减1(因为我们是从0开始索引的)。本例中最后一个索引是:
在这个范围内,我们可以访问任意的子串。用一个参数来调用切片操作符结果是一个单一字符,而使用一个数值范围(用)作为参数调用切片操作的参数会返回一串连续地字符。再强调一遍,对任何范围[start:end],我们可以访问到包括start在内到end(不包括end)的所有字符,换句话说,假设x是[start:end]中的一个索引值,那么有:start<=x<end。
使用不在允许范围(本例中是0到3)内的索引值会导致错误。上面的aString[2:4]却并没有出错,那是因为实际上它返回的是索引值2和3的值。但是直接拿4作为索引访问是不被允许的。
在进行反向索引操作时,是从-1开始,向字符串的开始方向计数,到字符串长度的负数为索引的结束。最末一个索引(也就是第一个字符)是这样定位的:
如果开始索引或者结束索引没有被指定,则分别以字符串的第一个和最后一个索引值为默认值。
注意:起始/结束索引都没有指定的话会返回整个字符串。
1. 成员操作符(in,not in)
成员操作符用于判断一个字符或者一个子串(中的字符)是否出现在另一个字符串中。出现则返回True,否则返回False。注意,成员操作符不是用来判断一个字符串是否包含另一个字符串的,这样的功能由find()或者index()(还有它们的兄弟:rfind()和rindex())函数来完成。
下面是一些字符串和成员操作符的例子。在Python 2.3以前,in(和not in)操作符只允许用来判断一个单个字符是否属于一个字符串,就像下面第2个例子那样。2.3以后这个限制去掉了,所有的字符串都可以拿来判断。
在例6.1里面,我们会用到下面这些string模块预定义的字符串:
例6.1是一个用来检查Python有效标识符的小脚本,名字是idcheck.py。我们知道,Python标识符必须以字母或下划线开头,后面跟字母、下划线或者数字。
例6.1 标识符检查(idcheck.py)
标识符合法性检查,首先要以字母或者下划线开始,后面要跟字母,下划线或者或数字。这个小例子只检查长度大于等于2的标识符。
这个例子还展示了字符串连接符(+)的使用,本章的后面会讲到字符串连接符。运行几次后得到下面的输出:
让我们逐行解释这个应用程序。
3 ~ 6行
导入string模块并且预定义了两个字符串,用于后面的判断。
8 ~ 12行
输出提示信息,第12行的if语句过滤掉长度小于2的标识符或者候选标识符。
14 ~ 16行
检查第一个符号是不是字母或下划线,如果不是,输出结果并退出。
17 ~ 18行
否则,从第二个字符开始到最后一个字符,循环检查剩余的字符。
20 ~ 23行
检查剩余的符号是否都是字母,下划线或者数字。注意我们是如何使用连接操作符来创建合法字符集合的。只要发现一个非法字符,就显示结果并通过break语句退出。
核心提示:性能
24 ~ 25行
或许现在就向你展示for-else循环语句有点儿早,可是我们必须先看一看这个语句(在第8章有详细的介绍)。for循环的else语句是一个可选项,它只在for循环完整的结束,没有遇到break时执行。在我们的例子中,如果所有的符号都检查合格,那么我们就得到了一个合法的标识符,程序会返回一个这样的结果,然后执行完毕。
其实,这段程序并不是完美的,一个问题就是标识符的长度必须大于1。我们的程序几乎是,但还并没有真正定义出Python标识符的范围,Python标识符长度可以是1。另一个问题是这段程序并没有考虑到Python的关键字,而这些都是作为保留字,不允许用做标识符的。我们把这两个问题作为课后练习留给读者(见练习6-2)。
2. 连接符(+)
运行时刻字符串连接
我们可以通过连接操作符来从原有字符串获得一个新的字符串。我们已经在前面的例6-1里面见识过连接符了,下面是一些更多的例子:
最后一个例子展示了用一个字符串s的两个切片来构成一个新串的操作,从“Spanish”里面切出“Spa”加上从“Made”里面切出来的“M”。将抽取出来字符串切片连接后作为参数传给了string.upper()方法,该方法负责把字符串的所有字符都变为大写。String模块的方法是在Pythonl.6里面添加进来的,所以这个操作也可以用最后一个字符串的一个单一方法调用来完成(见下面的例子)。现在已经没有必要导入string模块了,除非你需要访问该模块自己定义的字符串常量。注意:虽然对初学者来说string模块的方式更便于理解,但出于性能方面的考虑,我们还是建议你不要用string模块。原因是Python必须为每一个参加连接操作的字符串分配新的内存,包括新产生的字符串。取而代之,我们推荐你像下面介绍的那样使用字符串格式化操作符(%),或者把所有的字符串放到一个列表中去,然后用一个join()方法来把它们连接在一起。
3. 编译时字符串连接
上面的语法在运行时字符串连接的加法操作,这个用法是非常标准的。Python中还有一种并不是经常用到,更像是一种程序员的习惯用法的语法。Python的语法允许你在源码中把几个字符串连在一起写,以此来构建新字符串。
通过这种方法,你可以把长的字符串分成几部分来写,而不用加反斜杠。如上所示,你可以在一行里面混用两种分号。这种写法的好处是你可以把注释也加进来,如下所示。
如你所想,下面就是urlopen()方法所得到的真实输入。
4. 普通字符串转化为Unicode字符串
如果把一个普通字符串和一个Unicode字符串做连接处理,Python会在连接操作前先把普通字符串转化为Unicode字符串:
重复操作符创建一个包含了原有字符串的多个拷贝的新串。
像其他的标准操作符一样,原变量是不被修改的,就像上面最后一个例子所示。