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 name

    Sam
    Brad
    Alex
    Cameron
    Toby
    Gwen
    Jenn
    Connor

    空标题文档 - 图1

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

    >>> parts = name_string.split('Toby,')
    >>> print parts
    ['Sam,Brad,Alex,Cameron', 'Gwen,Jenn,Connor']

    >>> for part in parts:
    print part

    Sam,Brad,Alex,Cameron
    Gwen,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 Cake
    Ingredients:
    2 eggs
    1/2 cup flour
    1 tsp baking soda
    1 lb chocolate

    Instructions:
    Preheat oven to 350F
    Mix all ingredients together
    Bake 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空标题文档 - 图2 因为 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 = 0
    while not lines[i].startswith("Instructions"):
    i = i + 1

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

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

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

    657 Maple Lane
    47 Birch Street
    95 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。

    空标题文档 - 图3

    注意,使用 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() 要剥除哪一部分,它就会去除所有空白符。前面说过,这包括空格、制表符和换行符。所以,如果想要去除一些多余的空格,就可以这样做:

    空标题文档 - 图4

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

    改变大小写

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

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

    >>> string1 = "Hello"
    >>> string2 = string1.lower()
    >>> print string2
    hello

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

    >>> string3 = string1.upper()
    >>> print string3
    HELLO

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

    你学到了什么

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

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

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

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

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

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

    • 如何使用 startswith()、endswith()、in 和 index()。

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

    • 如何用 upper() 和 lower() 将字符串转换为全大写或全小写。

    测试题

    1. 如果有两个单独的 print 语句,如下:
    print "What is"
    print "your name?"

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

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

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

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

    动手试一试

    1. 编写一个程序,询问一个人的姓名、年龄和最喜欢的颜色,然后打印在一句话里。运行这个程序时应该看到类似这样的结果:
    >>> ======================== RESTART ========================
    >>>
    What is your name? Sam
    How old are you? 12
    What is your favorite color? green
    Your name is Sam you are 12 years old and you like green

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

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