
2.4 字符串
字符串是Python中常用的数据类型,在Python 3中字符串采用的是Unicode编码,也就是任何一个字符都用2字节表示。在Python中用单引号“'”或双引号“"”来创建字符串,如下所示:

由此可见,在Python中创建字符串并不是太难。只是在其他的语言中,很多开发者都喜欢使用str作为字符串变量的标识。而在Python中str是一个内置的函数名,所以就不能使用这个标识。此外,还可以将其他数据类型转变为字符串类型,具体如下:

运行上述代码得到的输出结果如下:

由此可见,变量a_str是一个字符串,而不是数字。当使用str作为变量标识时,就会覆盖str函数,如下所示:

运行上述代码得到的输出结果如下:

由此可见,上下文已经不能再识别str函数,因此需要记住不要使用str作为字符串变量的标识。
说明 在Python中只有数据类型字符串,没有字符数据类型。
在C/C++和Java中存在字符串和字符的数据类型,其中字符类型使用单引号,并且只能是一个字符。而在Python中,没有字符类型,只有字符串类型,哪怕使用单引号且只有一个字符,也是字符串,如下所示:

运行上述代码得到的输出结果如下:

由此可见,'a'是一个字符串,而不是一个字符。
2.4.1 截取子串
所谓子串是指一个字符串所包含的子集,如“人生”、“P”和“Python”都可以看成“人生苦短,我用Python”的子串。在Python中,可以通过“[]”和下标来截取字符串的子串,并且下标是以0开始的,下面通过代码清单2-16举例说明。
代码清单2-16:截取子串

这里首先使用了len函数,这样就会返回字符串的长度。需要注意的是“[]”中不同的参数表达。例如,s[2]表示取第3个字符作为子串;s[:4]表示截取前4个字符作为子串;s[5: ]表示截取下标为5(含)之后的字符作为子串;s[7: len(s)]表示截取下标为7到len(s)的子串,此时包含下标7,但是不包含下标len(s)。运行上述代码得到的输出结果如下:

说明 当截取字符串使用的下标不合理时会如何?
在上述例子中采用的是合理的下标,所以可以正确截取字符串。但是,如果下标不合理又会如何?例如,截取子串s[8:2]会返回什么呢?在Python中如果遇到不合理的下标,它就会返回''。下面在代码清单2-18的基础上增加如下几行代码进行测试:

运行上述代码得到的输出结果如下:

由此可见,当下标不合理时,它就会返回''。
实际上,在Python中除了可以使用0到len(s)表示字符串的下标,还可以使用负数来表示反向下标,在使用负数时,最后一个字符的下标为-1,而第一个字符的下标为-len(s),如图2-3所示。

图2-3 字符串下标图示(len(s)=13)
下面通过负数下标来截取子串,如代码清单2-17所示。
代码清单2-17:通过负数下标来截取子串

一般来说,在使用负数下标时需要先用len函数求出它的第一个字符的负数下标值,如代码中的-1*length就是字符串第一个字符的负数下标。然后通过减法来截取字符串,这样有利于提高代码的可读性。
注意 防止下标越界
在字符串中使用下标需要防止下标越界。如果发生越界,就会在运行过程中产生错误,如下所示:

这里的下标13和-14都已经超越了字符串的下标区间[0, 13)和[-13, 0),因此在运行时就会产生错误,输出如下结果:

为了防止下标越界,笔者先求出字符串的长度(length),然后根据长度控制来访问,如下所示:

上述代码先求出字符串的长度,然后保证下标在区间[0, length)或[-1*length, 0)访问字符串,就能够避免下标越界,这是开发者常用的技巧,而使用length作为变量名称,代码的可读性也会有所提高。
2.4.2 字符串的运算
在Python中,字符串本身也提供了许多运算功能,包括字符串连接、截取子串、判断是否为子串等。假设s="人生苦短,我用Python",下面通过表2-9来展示字符串的运算。
表2-9 字符串的运算

下面通过代码清单2-18来学习表2-9中的内容。
代码清单2-18:字符串的运算

需要注意最后的字符串连接数字,由于直接连接数字会发生异常,因此需要通过str函数将数字先转换为字符串才能进行连接。运行上述代码得到的输出结果如下:

2.4.3 字符串的格式化
为了连接字符串,经常需要使用连接符“+”,而有时过多的字符串会使可读性大大降低,如下所示:

显然,字符串output的可读性大大降低。这个时候可以考虑使用格式化的字符串来处理,在Python中可以使用“%”来格式化字符串,然后根据数据类型在字符串中使用不同的格式化符号,如可以使用以下代码来提高代码的可读性:

需要注意的是代码①中加粗的3个占位符,即“%s”、“%d”和“%.2f”。其中,“%s”表示一个字符串占位;“%d”表示一个数字占位;而“%.2f”表示浮点数占位,且精度保留2位小数。然后在字符串后面使用“%(参数列表)”的方式进行格式化,这样就可以通过参数来格式化字符串。此外,Python中还存在很多占位符,下面通过表2-10进行说明。
表2-10 字符串占位符

上面只是简单的格式化,功能还不够强大。为了增强格式化的功能,在Python 2.6版本之后,Python中还提供了字符串的format函数,用来增强格式化的功能,所以在新的版本中,Python官方建议使用format函数来格式化字符串,而不是使用“%”来格式化字符串。下面通过举例来说明format函数的使用方法,如代码清单2-19所示。
代码清单2-19:使用format函数格式化字符串


在代码①处、代码②和代码③处使用了换行符“\”,所以可以另起一行来编写format函数。在代码①处,通过指定参数位置(从0开始)来格式化字符串,而“:”后可以指定参数的数据类型并格式化,这样就可以通过参数的顺序来格式化字符串。在代码②处和代码③处使用了字典,在代码②处需要指定参数位置和字典的key;而在代码③处只需要指定字典的key,只是format函数的参数写作“**params”。使用字典可以让参数占位通过名称表达具体的含义,因此具备更高的可读性,并且不存在参数顺序的限制。
说明 再次强调可读性
在代码清单2-19中,代码②处和代码③处都可以使用字典作为参数进行格式化,显然后一种方式的可读性更高,因此笔者建议使用后一种方式进行编码。
2.4.4 Python转义字符
在计算机中还存在一些特殊的字符,如常见的换行符,在Python中约定使用"\n"来表示换行,除此之外,还规定了许多特殊的字符,它们都以反斜杠“\”开头。转义字符如表2-11所示。
表2-11 转义字符

在表2-11中,加粗的行在开发中经常用到,其他字符用得比较少,所以重点掌握常用的转义字符即可。当然,也可以取消转义字符,如下所示:

需要注意的是,字符串前的字符r(或R)表示字符串将不再进行转义。下面通过代码清单2-20来介绍这些常见的转义字符。
代码清单2-20:使用常见的转义字符

运行上述代码得到的输出结果如下:

此外,Python在多行中还提供了三引号(既可以是单引号,也可以是双引号)的编写,三引号让开发者从引号和换行等格式化的泥潭中解脱出来,它采取多行字符串所见即所得的方式来简化程序员的工作,如代码清单2-21所示。
代码清单2-21:三引号的使用


运行上述代码得到的输出结果如下:

2.4.5 字符串常用的函数
除了上述内容,Python的字符串还存在几十种方法可以对字符串进行操作,只是罗列它们非常枯燥,并且很多方法并不常用,所以本节只用代码清单2-22介绍常用的函数。
代码清单2-22:字符串中的常用函数


以上就是字符串常用的函数,代码中也给出了清晰的注释。
在Python 3.9及其之后的版本中还加入了两个新的函数,即removeprefix和removesuffix,它们的作用是删除指定的前缀和后缀,如下所示:

运行结果如下:

由此可见,对应的前缀和后缀被删除。