讀古今文學網 > 父與子的編程之旅:與小卡特一起學Python > 21.6 更多字符串處理 >

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 位小數。