字符串的基本操作
字符串是Python中最常用的數據類型。我們可以使用引號('或")創建字符串。創建字符串很簡單,只要為變量分配一個值即可。請看下面的例子:
>>> field='Hello' #創建字符串Hello,并賦給變量field
所有標準序列操作(如索引、分片、成員資格、求長度、取最小值和最大值等)對字符串同樣適用,我們在前面章節已經講解了這些操作。不過字符串是不可變的,所以字符串做不了分片賦值。請看如下操作:
>>> field='just do it'
>>> field[-3:]
' it'
>>> field[-3:]='now'
Traceback (most recent call last):
File "<pyshell#113>", line 1, in <module>
field[-3:]='now'
TypeError: 'str' object does not support item assignment
輸出結果告訴我們str類型的對象不支持更改。
我們講述了這么多字符串,還沒有看到如何在輸出語句中輸出兩行,這個操作該怎么實現呢?例如:
>>> print ('精誠所至\n金石為開')
精誠所至
金石為開
輸出結果為兩行,這里使用了轉義字符\n,表示換行。Python中有很多轉義符,表列出了一些常用的轉義字符。
對于前面的示例,若要以如下格式輸出,則需要使用轉義字符:
'精誠所至'
'金石為開'
例如:
>>> print (''精誠所至'\n'金石為開'') #不使用轉義字符
SyntaxError: invalid syntax
>>> print ('\'精誠所至\'\n\'金石為開\'') #使用\’轉義字符
'精誠所至'
'金石為開'
由操作結果可知,使用'轉義字符得到了想要的結果,不使用轉義字符不能輸出對應結果。在Python中進行字符串的操作時,如果涉及一些需要做轉義的操作,就要使用轉義字符。這些字符無須刻意記憶,先有一些了解即可,在后面的學習中結合實際操作會逐漸熟練使用。
字符串格式化
到目前為止,我們對字符串的操作都是停留在賦值、重新賦值、索引、分片和輸出等一些比較基本的操作上,其實字符串還有更多、更好的操作方式,比如在實際項目開發中經常使用的字符串格式化操作。
1 字符串格式化符號
字符串格式化使用操作符百分號(%)實現。
注意:%也可以用作模運(求余)操作符。
例如:
hello,world
>>> print ('小智今年%s 歲了' % 10)
小智今年10歲了
由上面輸入的內容可知,%左邊放置了一個待格式化的字符串,右邊放置的是希望格式化的值。格式化的值可以是一個字符串或數字。
格式化字符串的%s部分稱為轉換說明符,標記了需要放置轉換值的位置,通用術語為占位符。可以想象成在學校上自習,我們通常會放一個物品在一個位置上,其他人
一看就知道這個位置被占了,而我們無論什么時候去自習,直接到自己占好的位置坐下即可。這里可以把%s當作我們使用的物品,我們相當于后面%右邊的值。
在上面的示例中,s表示百分號右邊的值會被格式化為字符串,s指的是str。如果不是字符串,就會使用str將其轉換為字符串。示例中就將10轉換為字符串了,這種方式對大多數數值都有效。
這里提供了字符串格式化的方式,但若需要轉換為其他格式,該怎么辦呢?Python為我們提供了表所示的格式化符號。
根據表,前面的示例可以使用以下兩種方式:
>>> print ('小智今年%s 歲了' % 10) #使用%s 作為10 的占位符
小智今年10歲了
>>> print ('小智今年%d 歲了' % 10) #使用%d 作為10 的占位符
小智今年10歲了
由操作結果看到,整數既可以使用%s也可以使用%d進行格式化。
如果要格式化實數(浮點數),就可以使用%f進行格式化,例如:
>>> print ('圓周率PI 的值為:%f' % 3.14)
圓周率PI 的值為:3.140000
輸出結果中有很多位小數,但傳入的值只有兩位小數,要解決這個問題可以使用格式化符號。
從表4-2可知,%f可指定精度值。在Python中,使用%f時,若不指定精度,則默認輸出6位小數。
以指定2位小數為例,指定精度的格式如下:
%.2f
指定精度的格式為一個英文格式下的句點加上希望保留的小數位數。因為格式化說明符以表示類型的字符結束,所以精度應該放在類型字符前面。
使用這個格式更改上面圓周率輸出的示例:
>>> print ('圓周率PI 的值為:%.2f' % 3.14)
圓周率PI 的值為:3.14
輸出結果正是我們希望得到的。
表4-2中的符號不是所有都常用,比較常用的有%s、%d、%f三個,%e和%E在科學計算中使用比較多,其他符號了解就可以,有興趣也可以自行研究。
假如我們要輸出類似1.23%這樣的結果,直接使用加號加一個百分號可以嗎?嘗試如下:
>>> print ('小智的識別能力比去年提高了:%.2f' % 1.23+'%')
小智的識別能力比去年提高了:1.23%
輸出結果得到了我們想要的,說明這種方式可以。不過輸入的代碼看起來怪怪的,有沒有更好的辦法呢?例如:
>>> print ('小智的識別能力比去年提高了:%.2f%%' % 1.23)
小智的識別能力比去年提高了:1.23%
用這種方式也得到了我們想要的結果。不過我們在f字符后面使用了兩個%,結果只輸出了一個,這是怎么回事?
在Python中,字符串中的百分號是轉換說明符,如果要輸出%,就需要格式化字符%,從而需要使用%%。使用這種方式操作的功能類似:
>>> print ('輸出百分號:%s' % '%')
輸出百分號:%
2 字符串格式化元組
格式化操作符的右操作數可以是任何元素。如果是元組或映射類型(如字典,下一章進行講解),那么字符串格式化將會有所不同。我們尚未涉及映射(字典),這里先了解一下元組。
如果右操作數是元組,其中每一個元素都會被單獨格式化,每個值都需要一個對應的轉換說明符。例如:
>>> print ('今年是%s 年,中國女排奪得本屆奧運會%s,中國共獲得%d 枚金牌'%('2016','冠軍',26))
今年是2016年,中國女排奪得本屆奧運會冠軍,中國共獲得26 枚金牌
>>> print ('今年是%s 年,中國女排奪得本屆奧運會%s,中國共獲得%d 枚金牌' % '2016','冠軍',26)
Traceback (most recent call last):
File "<pyshell#149>", line 1, in <module>
print ('今年是%s 年,中國女排奪得本屆奧運會%s,中國共獲得%d 枚金牌' % '2016','冠軍',26)
TypeError: not enough arguments for format
由以上輸出結果看到,在有多個占位符的字符串中,可以使用元組傳入多個格式化值。如果需要轉換的元組作為轉換表達式的一部分存在,就必須將它用圓括號括起來,否則會出錯。
如果使用列表或其他序列代替元組,序列就會被解釋為一個值。只有元組和字典可以格式化一個以上的值。
下面介紹基本轉換說明符。注意,這些項的順序是至關重要的。
(1)%字符:標記轉換說明符開始。
(2)轉換標志(可選):-表示對齊;+表示在轉換值之前要加上正負號;“”(空白字符)表示正數之前保留空格;0表示轉換值位數不夠時用0填充。
(3)最小字段寬度(可選):轉換后的字符串至少應該具有該值指定的寬度。如果是,寬度就會從值元組中讀出。
(4)點(.)后跟精度值(可選):如果轉換的是實數,精度值表示出現在小數點后的位數;如果轉換的是字符串,該數字就表示最大字段寬度;如果是,精度就會從元組中讀出。
(5)轉換類型:上面圖表所示
下面將詳細討論上述5個注意項。
1. 簡單轉換
例如,輸入以下代碼:
>>> print ('圓周率PI 的值為:%.2f' % 3.14)
圓周率PI 的值為:3.14
>>> print ('石油價格為每桶:$%d' % 96)
石油價格為每桶:$96
由上面的輸出結果可以看到,簡單轉換只需要寫出轉換類型,使用起來很簡單。
2. 字段寬度和精度
轉換說明符包括字段寬度和精度。字段寬度是轉換后的值所保留的最小字符個數,精度是數字轉換結果中應該包含的小數位數或字符串轉換后的值所能包含的最大字符個數。
例如:
>>> print ('圓周率PI 的值為:%10f' % 3.141593) #字段寬度為10
圓周率PI 的值為: 3.141593 #字符串寬度為10,被字符串占據8 個空格,剩余兩個空格
>>> print ('保留2 位小數,圓周率PI 的值為:%10.2f' % 3.141593) #字段寬度為10
保留2 位小數,圓周率PI 的值為: 3.14 #字符串寬度為10,字符串占據4 個,剩6 個
>>> print ('保留2 位小數,圓周率PI 的值為:%.2f' % 3.141593)
保留2 位小數,圓周率PI 的值為:3.14 #輸出,沒有字段寬度參數
>>> print ('字符串精度獲取:%.5s' % ('hello world')) #打印字符串前5 個字符
字符串精度獲取:hello
由輸出結果可知,字段寬度和精度都是整數,并通過點號(.)分隔。兩個都是可選參數,如果給出精度,就必須包含點號。
再看以下代碼:
>>> print ('從元組中獲取字符串精度:%*.*s' % (10,5,'hello world'))
從元組中獲取字符串精度: hello
>>> print ('從元組中獲取字符串精度:%.*s' % (5,'hello world'))
從元組中獲取字符串精度:hello #輸出精度為5
由輸出結果看到,可以使用(星號)作為字段寬度或精度(或兩者都用),數值會從元組中讀出。
3. 符號、對齊和0填充
開始介紹之前先看一個示例:
>>> print ('圓周率PI 的值為:%010.2f' % 3.141593)
圓周率PI 的值為:0000003.14
輸出結果是不是怪怪的,這個我們稱之為“標表”。在字段寬度和精度之前可以放置一個“標表”,可以是零、加號、減號或空格。零表示用0進行填充。
減號(-)用來左對齊數值,例如:
>>> print ('圓周率PI 的值為:%10.2f' % 3.14)
圓周率PI 的值為: 3.14
>>> print ('圓周率PI 的值為:%-10.2f' % 3.14)
圓周率PI 的值為:3.14 #此處右側為多出的空格
從輸出結果看到,使用減號時,數字右側多出了額外的空格。
空白(“”)表示在正數前加上空格,例如:
>>> print(('%5d'%10)+'\n'+('%5d'%-10))
10
-10
由輸出結果可以看到,該操作可以用于對齊正負數。
加號(+)表示無論是正數還是負數都表示出符號,例如:
>>> print(('寬度前加加號:%+5d'%10)+'\n'+('寬度前加加號:%+5d'%-10))
寬度前加加號: +10
寬度前加加號: -10
該操作也可以用于數值的對齊。
3 字符串方法
字符串的方法比列表還多,因為字符串從string模塊中“繼承”了很多方法。
因為字符串的方法比較多,所示這里只介紹一些特別有用的方法。
1 find()方法
find()方法用于檢測字符串中是否包含子字符串str。如果指定beg(開始)和end(結束)范圍,就檢查是否包含在指定范圍內。如果包含子字符串,就返回開始的索引值;否則返回-1。
find()方法的語法如下:
str.find(str, beg=0, end=len(string))
此語法中str代表指定檢索的字符串,beg代表開始索引,默認為0;end代表結束索引,默認為字符串的長度。返回結果為子串所在位置的最左端索引,如果沒有找到,就返回-1。
該方法使用示例如下:
>>> field.find('do')
0
>>> field.find('now')
6
>>> field.find('python')
-1
由輸出結果看到,如果找到字符串,就返回對應的索引值;如果沒找到字符串;就返回-1。
注意:字符串的find方法返回的不是布爾值。如果返回0,就表示在索引0處找到了子字符串。
find方法還可以接受參數,用于表示起始點和結束點,例如:
>>> field.find('it',2) #提供起點
3
>>> field.find('it',5) #提供起點
-1
>>> field.find('it',0,3) #提供起點和終點
-1
>>> field.find('it',0,5)
3
>>> field.find('it',5,10)
-1
由輸出結果看到,可以通過使用起始值和終止值查找指定的范圍內是否存在指定字符串。
2 join()方法
join()方法用于將序列中的元素以指定字符連接成一個新字符串。
join()方法的語法如下:
str.join(sequence)
此語法中str代表指定檢索的字符串,sequence代表要連接的元素序列。返回結果為指定字符連接序列中元素后生成的新字符串。
該方法使用示例如下:
>>> num=[1,2,3,4,5]
>>> mark.join(num)
Traceback (most recent call last):
File "<pyshell#219>", line 1, in <module>
mark.join(num)
TypeError: sequence item 0: expected str instance, int found
>>> num.join(mark)
Traceback (most recent call last):
File "<pyshell#216>", line 1, in <module>
num.join(mark)
AttributeError: 'list' object has no attribute 'join'
>>> field=['1','2','3','4','5']
>>> print('連接字符串列表:',mark.join(field))
連接字符串列表: 1+2+3+4+5
>>> field.join(mark)
Traceback (most recent call last):
File "<pyshell#228>", line 1, in <module>
field.join(mark)
AttributeError: 'list' object has no attri
>>> dirs='','home','data','hdfs'
>>> print('路徑:','/'.join(dirs))
路徑: /home/data/hdfs
由輸出結果看到,進行join操作調用和被調用的對象必須都是字符串,任意一個不是字符串都會報錯。
3 lower()方法
lower()方法用于將字符串中所有大寫字符轉換為小寫。
lower()方法的語法如下:
str.lower()
此語法中str代表指定檢索的字符串,該方法不需要參數。返回結果為字符串中所有大寫字符轉換為小寫后生成的字符串。
該方法使用示例如下:
>>> field='DO IT NOW'
>>> print('調用lower 得到字符串:',field.lower())
調用lower 得到字符串: do it now
>>> greeting='Hello,World'
>>> print('調用lower 得到字符串:',greeting.lower())
調用lower 得到字符串: hello,world
由輸出結果看到,字符串中的大寫字母全部轉換為小寫字母了。
如果想要編寫“不區分大小寫”的代碼,就可以使用lower方法。如果想要在一個字符串中查找某個子字符串并忽略大小寫,也可以使用lower方法,操作如下:
>>> field='DO IT NOW'
>>> field.find('It') #都不轉換為小寫,找不到匹配字符串
-1
>>> field.lower().find('It') #被查找字符串不轉換為小寫,找不到匹配字符串
-1
>>> field.lower().find('It'.lower()) #使用lower 方法轉換成小寫后查找
3
由輸出結果看到,字符串全部轉換為小寫后能匹配到對應子串。
注意:有時類似于lower這樣的字符串方法并不能如我們所愿進行工作。對于英文字符串,lower方法在處理時一點問題都沒有;對于非英文字符串,lower方法在處理時可能不如我們的預期,如中文、挪威文等。
4 upper()方法
upper()方法用于將字符串中的小寫字母轉換為大寫字母。
upper()方法語法如下:
str.upper()
此語法中str代表指定檢索的字符串,該方法不需要參數。返回結果為小寫字母轉換為大寫字母的字符串。
該方法使用示例如下:
>>> field='do it now'
>>> print('調用upper 得到字符串:',field.upper())
調用upper 得到字符串: DO IT NOW
>>> greeting='Hello,World'
>>> print('調用upper 得到字符串:',greeting.upper())
調用upper 得到字符串: HELLO,WORLD
由輸出結果看到,字符串中的小寫字母全部轉換為大寫字母了。
如果想要編寫“不區分大小寫”的代碼,就可以使用upper方法。如果想要在一個字符串中查找某個子字符串并忽略大小寫,也可以使用upper方法,操作如下:
>>> field='do it now'
>>> field.find('It') #都不轉換為大寫,找不到匹配字符串
-1
>>> field.upper().find('It') #被查找字符串不轉換為大寫,找不到匹配字符串
-1
>>> field.upper().find('It'.upper()) #使用upper 方法轉換為大寫后查找
3
由輸出結果看到,字符串全部轉換為大寫后能找到對應子串。
5 swapcase()方法
swapcase()方法用于對字符串的大小寫字母進行轉換,將字符串中大寫轉換為小寫、小寫轉換為大寫。
swapcase()方法的語法如下:
str.swapcase()
此語法中str代表指定檢索的字符串,該方法不需要參數。返回結果為大小寫字母轉換后生成的新字符串。
該方法使用示例如下:
>>> field='Just do it,NOW'
>>> print('原字符串:',field)
原字符串: Just do it,NOW
>>> print('調用swapcase 方法后得到的字符串:',field.swapcase())
調用swapcase 方法后得到的字符串: jUST DO IT,now
由輸出結果看到,調用該方法后,輸出結果中的大寫字母變為小寫、小寫字母變為大寫。該方法進行大小寫轉換非常方便。
6 replace()方法
replace()方法把字符串中的old(舊字符串)替換成new(新字符串),如果指定第3個參數max,替換次數就不超過max次。
replace()方法的語法如下:
str.replace(old, new[, max])
此語法中str代表指定檢索的字符串;old代表將被替換的子字符串;new代表新字符串,用于替換old子字符串;max代表可選字符串,替換次數不超過max次。返回結果為字符串中的old(舊字符串)替換成new(新字符串)后生成的新字符串,如果指定第3個參數max,替換次數就不超過max次。
該方法使用示例如下:
>>> field='do it now,do right now'
>>> print('原字符串:',field)
原字符串: do it now,do right now
>>> print('新字符串:',field.replace('do','Just do'))
新字符串: Just do it now,Just do right now
>>> print('新字符串:',field.replace('o','Just',1))
新字符串: dJust it now,do right now
>>> print('新字符串:',field.replace('o','Just',2))
新字符串: dJust it nJustw,do right now
>>> print('新字符串:',field.replace('o','Just',3))
新字符串: dJust it nJustw,dJust right now
由上面輸出結果看到,當不指定第3個參數時,所有匹配字符都替換;指定第3個字符時,替換從左往右進行,替換次數不超過指定次數。
7 split()方法
split()方法通過指定分隔符對字符串進行切片,如果參數num有指定值,就只分隔num個子字符串。這是一個非常重要的字符串方法,是join的逆方法,用來將字符串分割成序列。
split()方法的語法如下:
str.split(st="", num=string.count(str))
此語法中str代表指定檢索的字符串;st代表分隔符,默認為空格;num代表分割次數。返回結果為分割后的字符串列表。
該方法使用示例如下:
>>> field='do it now'
>>> print('不提供任何分割符分隔后的字符串:',field.split())
不提供任何分割符分隔后的字符串: ['do', 'it', 'now']
>>> print('根據i分隔后的字符串:',field.split('i'))
根據i分隔后的字符串: ['do ', 't now']
>>> print('根據o 分隔后的字符串:',field.split('o'))
根據o 分隔后的字符串: ['d',' it n', 'w']
>>> print('根據o 分隔1 次后的字符串:',field.split('o',1))
根據o 分隔1 次后的字符串: ['d',' it now']
由輸出結果看到,如果不提供分隔符,程序就會把所有空格作為分割符。操作中可以指定分隔符和分割次數,若指定分割次數,則從左往右檢索和分隔符匹配的字符,分割次數不超過指定次數;若不指分割次數,則所有匹配的字符都會被分割。
8 strip()方法
strip()方法用于移除字符串頭尾指定的字符(默認為空格)。
strip()方法的語法如下:
str.strip([chars])
此語法中str代表指定檢索的字符串,chars代表移除字符串頭尾指定的字符。返回結果為移除字符串頭尾指定的字符生成的新字符串。
該方法使用示例如下:
>>> field='----do it now----'
>>> print('原字符串:',field)
原字符串: ----do it now----
>>> print('新字符串:',field.strip('-'))
新字符串: do it now
>>> st='----do -- it -- now----'
>>> print('原字符串:',st)
原字符串: ----do -- it -- now----
>>> print('新字符串:',st.strip('-'))
新字符串: do -- it -- now
由操作結果看到,strip方法只去除頭尾匹配的字符,中間匹配的字符不會去除。
9 translate()方法
translate()方法根據參數table給出的表(包含256個字符)轉換字符串的字符,將要過濾掉的字符放到del參數中。
translate()方法的語法如下:
str.translate(table[, deletechars])
此語法中str代表指定檢索的字符串;table代表翻譯表,翻譯表通過maketrans方法轉換而來;deletechars代表字符串中要過濾的字符列表。返回結果為翻譯后的字符串。
該方法使用示例如下:
>>> intab='adfas'
>>> outtab='12345'
>>> trantab=str.maketrans(intab,outtab)
>>> st='just do it'
>>> print('st 調用translate 方法后:',st.translate(trantab))
st調用translate方法后: ju5t 2o it
由輸出結果看到,有幾個字符被替換成數字了,被替換的字符既在intab變量中,又在st變量中,如下圖所示。對于既在intab中,又在st中的字符,使用outtab中對應的字符替換。由下面圖可知,intab中的字符d對應outtab中的字符2、字符s對應字符5,所以最后輸出字符串中的s被替換成5、d被替換成2,這樣就得到了最后我們看到的字符串js5t 2o it。
ranslate方法和replace方法一樣,可以替換字符串中某些部分。和replace方法不同的是,translate方法只處理單個字符。translate方法的優勢在于可以同時進行多個替換,有時比replace方法效率高得多。
調試
這里通過設置的一些錯誤讓讀者認識在編寫代碼過程中的常見問題,以幫助讀者熟悉和解決實際遇到的問題。
(1)使用格式化整數的占位符格式化字符串,例如:
>>> print ('hello,%d' % 'world')
Traceback (most recent call last):
File "<pyshell#120>", line 1, in <module>
print ('hello,%d' % 'world')
TypeError: %d format: a number is required, not str
輸出結果告訴我們需要一個數字,而不是字符串。
(2)在使用%f輸出圓周率的示例中,若更改為使用%d輸出,結果會怎樣?輸入如下:
>>> print ('圓周率PI 的值為:%d' % 3.14)
圓周率PI 的值為:3
結果把小數點后的數值都拋棄了。
(3)在用0填充的示例中,把010的第一個0更改為其他數字,看看輸出結果。再在精度之前添加一個0或大于0、小于0的數字,看看輸出結果。
>>> print ('圓周率PI 的值為:%06.2f' % 3.141593)
圓周率PI 的值為:003.14
>>> print ('圓周率PI 的值為:%16.2f' % 3.141593)
圓周率PI 的值為: 3.14
>>> print ('圓周率PI 的值為:%.02f' % 3.141593)
圓周率PI 的值為:3.14
>>> print ('圓周率PI 的值為:%.12f' % 3.141593)
圓周率PI 的值為:3.141593000000
>>> print ('圓周率PI 的值為:%.-12f' % 3.141593)
Traceback (most recent call last):
File "<pyshell#179>", line 1, in <module>
print ('圓周率PI 的值為:%.-12f' % 3.141593)
ValueError: unsupported format character '-' (0x2d) at index 11
由輸出結果看到,將寬度前面的0更改為其他數字會認作寬度值,而不是填充值。在精度前面加0對結果沒有影響;若添加大于0的數字,則作為小數的實際位數輸出,位數不夠后面補0;若添加小于0的數字,則報異常。