首页 » 父与子的编程之旅:与小卡特一起学Python » 父与子的编程之旅:与小卡特一起学Python全文在线阅读

《父与子的编程之旅:与小卡特一起学Python》21.6 更多字符串处理

关灯直达底部

最早学习字符串时(第 2 章),我们已经看到,可以用 + 号把两个字符串联接起来,就像这样:

>>> print /'cat/' + /'dog/'catdog  

现在来看还可以对字符串做哪些处理。

Python 中的字符串实际上都是对象(看到了吧,所有一切都是对象……),而且有自己的方法来完成搜索、分解和结合之类的操作。这些方法都称为字符串方法。刚刚看到的 format 方法就是一种字符串方法。

分解字符串

有时需要把一个长字符串分解成多个小字符串。通常你会想在字符串的某些特定位置(比如说出现某个字符的地方)进行分解。例如,在文本文件中存储数据时,常见的方法就是将各个项用逗号分隔。所以你可能会得到类似这样一个名字字符串:

>>> name_string = /'Sam,Brad,Alex,Cameron,Toby,Gwen,Jenn,Connor/'  

假设你想把这些名字放在一个列表中,每一项是一个名字。这就需要在出现逗号的地方分解字符串。完成这项工作的 Python 方法名为 split,它的用法如下:

>>> names = name_string.split(/',/')  

要指出使用哪个字符作为分解标记,这个方法会返回一个列表,也就是把原来的字符串分解为许多部分。如果打印这个例子的输出,这个长长的名字串会分解为一个列表中的单个列表项:

>>> print names[/'Sam/',/'Brad/',/'Alex/',/'Cameron/',/'Toby/',/'Gwen/',/'Jenn/',/'Connor/']>>> for name in names:print nameSamBradAlexCameronTobyGwenJennConnor  

也可以用多个字符作为分解标记。例如,可以使用 /'Toby,/' 作为分解标记,这会得到下面的列表:

>>> parts = name_string.split(/'Toby,/')>>> print parts[/'Sam,Brad,Alex,Cameron/', /'Gwen,Jenn,Connor/']>>> for part in parts:      print partSam,Brad,Alex,CameronGwen,Jenn,Connor  

这一次,字符串会分解为两部分:/'Toby,/' 左侧的所有内容,以及 /'Toby,/' 右侧的所有内容。注意 /'Toby,/' 并没有出现在列表中,因为分解标记会被丢掉。

还有一点要知道。如果没有为 Python 指定任何分解标记,它会按空白符(whitespace)分解字符串:

>>> names = name_string.split  

空白符表示所有空格、制表符或换行符。

联接字符串

我们刚才了解了如何把一个字符串分解为较小的部分。那么怎样把两个或多个字符串联接起来构成一个较长的字符串呢?(在第 2 章中)我们已经了解到,可以使用 + 操作符把字符串联接起来。这就像把两个字符串相加,只不过这称为拼接(concatenating)。

联接字符串还有一种方法。可以使用 join 函数。你要指出你希望把哪些字符串联接起来,另外希望在联接的各部分之间插入什么字符(如果有的话)。这实际上与 split 正相反。下面是交互模式中完成的一个例子:

>>> word_list = [/'My/', /'name/', /'is/', /'Warren/']>>> long_string = /' /'.join(word_list)>>> long_string/'My name is Warren/'  

我得承认这看起来有些怪异。要联接的各个字符串之间可以插入字符,而且这个字符居然放在 join 前面。在这里,我们希望每个词之间有一个空格,所以使用了 /'/'.join。大多数人可能都没有想到会是这样,不过 Python 的 join 方法确实要这样使用。

下面这个例子会让人觉得我是只小狗:

>>> long_string = /' WOOF WOOF /'.join(word_list)>>> long_string/'My WOOF WOOF name WOOF WOOF is WOOF WOOF Warren/'  

换句话说,join 前面的字符串可以用作粘合剂,把其他字符串联接在一起。

搜索字符串

假设你想为妈妈创建一个程序,获取食谱并在 GUI 中显示。你想在一个位置显示配料,在另一个位置显示做法。假设食谱是这样的。

Chocolate CakeIngredients:2 eggs1/2 cup flour1 tsp baking soda1 lb chocolateInstructions:Preheat oven to 350FMix all ingredients togetherBake for 30 minutes  

假设食谱中的各行都被放在一个列表中,每一行在列表中都是单独的元素。怎么找到“Instructions”(做法)部分呢?Python 提供了两种有用的方法。

startswith 方法可以指出一个字符串是否以某个字符或某几个字符开头。举个例子最能说明问题。在交互模式中试试下面的例子。

>>> name = /"Frankenstein/">>> name.startswith(/'F/')True>>> name.startswith(/"Frank/")True>>> name.startswith(/"Flop/")False 

名字 Frankenstein 确实以字母 F 开头,所以第一个结果是 True。名字 Frankenstein 确实以 Frank 开头,所以第二个结果也是 True。不过,名字 Frankenstein 不是以 Flop 开头,所以这一个结果是 False

因为 startswith 方法返回一个 TrueFalse 值,所以可以在比较或 if 语句中使用这个方法,比如可以这样:

>>> if name.startswith(/"Frank/"):print /"Can I call you Frank?/"  

还有一个类似的方法,名为 endswith,从这个方法名你应该可以想到它会做什么。

>>> name = /"Frankenstein/">>> name.endswith(/'n/')True>>> name.endswith(/'stein/')True>>> name.endswith(/'stone/')False  

现在,回到我们的问题……如果想找到食谱的“Instructions”部分从哪里开始,可以这样做:

i = 0while not lines[i].startswith(/"Instructions/"):    i = i + 1  

这个代码会一直循环,直到找到以“Instructions”开头的一行。应该记得,lines[i] 表示 ilines 的索引。所以要从 lines[0](第 1 行)开始,然后是 lines[1](第 2 行),依此类推。while 循环结束时,i 会等于“Instructions”开头的那一行的索引,这正是你要找的位置。

在字符串中搜索:inindex

startswithendswith 方法可以很好地查找位于字符串开头和末尾位置的内容。不过如果想在一个字符串中间找某个内容呢?

下面假设你有一些包含街道地址的字符串,如下:

657 Maple Lane47 Birch Street95 Maple Drive  

也许你想找出所有包含 Maple 的地址。这里所有字符串都不是以 Maple 开头或结尾的,但是其中有两个确实包含有单词 Maple。怎么找到它们呢?

实际上,我们已经知道怎么做了。前面讨论列表时(第 12 章),曾经见过可以用这种方法来检查某个元素是否在一个列表中:

if someItem in my_list:    print /"Found it!/"  

这里使用了关键字 in 来检查某个元素是否在列表中。关键字 in 也同样适用于字符串。实际上字符串就是一个字符列表,

所以可以这样做:

>>> addr1 = /'657 Maple Lane/'>>> if /'Maple/' in addr1:print /"That address has /'Maple/' in it./"  

术语箱

在较大的字符串(如 657 Maple Lane)中查找较小的字符串(如 Maple)时,较小的这个字符串称为子串(substring)。

in 关键字只能指出子串是不是位于你检查的字符串中的某个位置,但没有告诉你它到底在什么位置。要得到这个位置,需要使用 index 方法。类似于搜索列表,index 会指出较小串从较大字符串中的哪个位置开始。右面是一个例子。

>>> addr1 = /'657 Maple Lane/'>>> if /'Maple/' in addr1:position = addr1.index(/'Maple/')print /"found /'Maple/' at index/", position  

如果运行这个代码,会得到右面的输出:

found /'Maple/' at index 4  

单词 Maple 从字符串 657 Maple Lane 的位置 4 开始。与列表一样,字符串中字母的索引(或位置)都是从 0 开始,所以 M 位于索引 4。

注意,使用 index 之前,我们首先用 in 查看子串 Maple 是不是确实在较大的字符串中。这是因为,如果使用了 index,而你查找的内容不在字符串中,就会得到一条错误消息。先用 in 检查可以杜绝这样的错误。在第 12 章中我们对列表也是这样做的。

删除字符串的一部分

你可能常常希望删除或剥除字符串的某一部分。通常,你希望剥除末尾部分,如换行符或一些多余的空格。Python 提供了一个字符串方法 strip,完全可以做到这一点。只需要告诉它你想剥除哪一部分,如下:

>>> name = /'Warren Sande/'>>> short_name = name.strip(/'de/')>>> short_name/'Warren San/'  

在这里剥除了我名字末尾的 de。如果末尾根本没有 de,那么什么也不会剥除:

>>> name = /'Bart Simpson/'>>> short_name = name.strip(/'de/')>>> short_name/'Bart Simpson/'  

如果没有告诉 strip 要剥除哪一部分,它就会去除所有空白符。前面说过,这包括空格、制表符和换行符。所以,如果想要去除一些多余的空格,就可以这样做:

注意我名字后面多余的空格都已经删除。这里有一点很好:你不需要告诉 strip 要删除多少个空格,它会删除字符串末尾的所有空白符。

改变大小写

我还要告诉你两种字符串方法。可以使用这两种方法把字符串从大写转换为小写,或者反过来,从小写转换为大写。有时你可能希望比较两个字符串,比如 Hello 和 hello,你想知道它们包含的字母是不是相同(尽管大小写可能不完全一样)。一种办法是让两个字符串中的所有字母都变成小写,然后完成比较。

Python 为此提供了一个字符串方法,名为 lower。可以在交互模式中试试下面的命令:

>>> string1 = /"Hello/">>> string2 = string1.lower>>> print string2hello  

还有一个类似的方法,名为 upper

>>> string3 = string1.upper>>> print string3HELLO  

可以为原来的字符串建立全小写(或全大写)的副本,然后比较这两个副本,看看它们是否相同(忽略大小写)。

你学到了什么

在这一章,你学到了以下内容。

  • 如何调整垂直间隔(添加或删除换行符)。

  • 如何用制表符设置水平间隔。

  • 如果使用格式字符串显示不同的数字格式。

  • 使用格式字符串的两种方法:% 符号和 format 方法。

  • 如何用 split 分解字符串和用 join 联接字符串。

  • 如何使用 startswithendswithinindex

  • 如何用 strip 去除字符串末尾的部分。

  • 如何用 upperlower 将字符串转换为全大写或全小写。

测试题

1. 如果有两个单独的 print 语句,如下:

print /"What is/"print /"your name?/"  

怎样把所有内容都打印在同一行上?

2. 打印时如何增加额外的空行?

3. 实现按列对齐时要使用哪一个特殊打印代码?

4. 使用哪个格式字符串强制按 E 记法打印一个数?

动手试一试

1. 编写一个程序,询问一个人的姓名、年龄和最喜欢的颜色,然后打印在一句话里。运行这个程序时应该看到类似这样的结果:

>>> ======================== RESTART ========================>>>What is your name? SamHow old are you? 12What is your favorite color? greenYour name is Sam you are 12 years old and you like green  

2. 还记得第 8 章中的乘法表程序(代码清单 8-5)吗?现在编写这个程序的一个改进版本,使用制表符确保所有内容都能很好地按列对齐。

3. 编写一个程序计算 8 的所有分数(例如,1/8, 2/8, 3/8……直到 8/8),要显示 3 位小数。