官术网_书友最值得收藏!

2.2 字符串

字符串是我們最常用的數據類型,也是六大類型中最重要、知識點最多的數據類型,所以,如果此刻的你正在犯困,請伸個懶腰,然后跟著我的步驟拿下字符串。顧名思義,所謂字符串就是一串字符,我想你應該知道什么是字符,如果不知道的話,我們有必要先來認識一下字符。

2.2.1 字符編碼

前面我們說了,計算機只能識別通電和斷電兩種信號,這種特點被設計成由0和1組成的二進制數據,而二進制又可以輕易轉換成十進制或其他進制,即擴展到整數。如果我們想表示字符,可以通過十進制數映射,比如說十進制65表示“A”,十進制66表示“B”,這種映射我們把它叫作編碼,比較典型的一種編碼叫作ASCII編碼,如表 2-1所示。

表2-1 ASCII對照表

續表

在計算機中1個二進制數稱為1位或1比特(Bit),8比特表示1字節(Byte),即8個二進制數表示1字節,表示為8Bit=1Byte,ASCII編碼是7位或8位表示一個字符,前者叫標準ASCII,后者叫拓展ASCII,所以拓展ASCII編碼的每個字符占用一個字節。字符“A”對應的十進制是65,二進制是01000001,可以看出如果轉換成二進制的數據后位數不夠8位會在左邊補0。而8位二進制數的最大值是11111111,即十進制的255,換一句話說,ASCII最多能表示256(0~255)個字符,能滿足英文編碼,因為英文只有26個字母再加上其他一些符號,256個字符基本夠用了,但其他語言,比如說我們的漢字就有九萬多個,更別說世界上還有那么多個國家和地區的語言符號,ASCII明顯不能滿足編碼需求。于是,很多國家都開始有了自己的編碼,比如說中國用gbk編碼表示中文字符,這樣造成的結果就是編碼混亂,所以你有時候打開一份文件看到的是亂碼,很可能是沒有指定正確的解碼方式。

為了統一編碼,后來出現了一種叫作Unicode的編碼,意在用一種編碼表示全世界的字符,雖然可行,但這種編碼統一用2字節進行編碼,本來1個英文字符只需要1字節就能表示,非要弄成2個字節,占用的資源就多了一倍,明顯不太友好。后來又經過改善,出現了一種叫作utf-8的編碼,這種編碼可以動態改變字節數,比如說英文字符占用1字節,常用漢字占用3字節,偏僻漢字占用4~6字節,這樣既能表示全世界的字符,又盡可能節省資源。正是由于utf-8這種可以節省資源的特性,現在該編碼已經得到廣泛應用,后面我們在進行文件操作的時候也經常使用這種編碼。

說了那么多,大家應該已經了解什么是字符了,簡單來說,字符就是經過某種編碼得到的符號,比如字母、漢字、標點符號等都屬于字符。我們記不住那么多字符,如果你想查看某個字符或編碼的ASCII映射,我們可以通過Python提供的ord()和chr()函數,代碼如下:

print(ord("A"))  # 輸出:65
print(ord("a"))  # 輸出:97
print(chr(65))  # 輸出:A

從上面的代碼可以看出字符“A”和字符“a”的ASCII是不一樣的,這也是為什么Python要嚴格區分大小寫的原因。

2.2.2 字符串

字符是單個的,如果把多個字符連在一起就成了字符串,所以本質上字符串就是字符。在Python中,字符串的類型是str,寫法是用半角引號把字符引起來,可以是單引號、雙引號或者三引號,只要用了引號就是字符串。注意兩點:引號必須是半角的,也必須成對出現。代碼如下:

a = 'hello'
print(type(a), a)  # 輸出:<class 'str'> hello
b = "hello"
print(type(b), b)  # <class 'str'> hello
c = '''Python'''
print(type(c), c)  # 輸出:<class 'str'> Python
d = """Python"""
print(type(d), d)  # 輸出:<class 'str'> Python

上面的代碼中變量a、b、c、d都是字符串,a和b完全等價,c和d完全等價。在用法上,單引號和雙引號沒有任何區別,但三引號就不一樣了,三引號可以保留換行而單引號和雙引號不行,如果你需要在單引號或雙引號里換行,要用到“\n”這個換行符,下面的兩種寫法是完全等價的。代碼如下:

print("\n誰言別后終無悔,\n寒月清宵綺夢回。\n深知身在情長在,\n前塵不共彩
云飛。\n")
print("""
誰言別后終無悔,
寒月清宵綺夢回。
深知身在情長在,
前塵不共彩云飛。
""")

正是由于三引號里的字符串可以隨意換行,所以很多人都喜歡把注釋內容寫在三引號里,因為如果使用“#”寫注釋,那么每行文本前面都要加上一個“#”,就顯得有點麻煩了。

那么多種引號都能表示字符串,而引號又必須成對出現,所以我們要靈活使用引號。如果一個字符串里面需要用到引號,有兩種解決辦法:一種是改變最外層的引號,比如說字符串內部包含了單引號或三引號,可以使用雙引號表示字符;另一種是在引號前面加一個反斜杠進行轉義,代碼如下:

print("It's very cool!")  # 輸出:It's very cool!
print('It\'s very cool!')  # 輸出:It's very cool!

第一種方法很容易理解,用最外面的一對雙引號表示字符串,字符串里面就算有成對單引號或三引號,只要沒有其他雙引號,這個字符串就不會有問題。第二種寫法是用最外面的一對單引號表示字符串,雖然內部也出現了單引號,但給這個單引號加了一個反斜杠,表示對其轉義,即告訴Python,內部的單引號只是一個普通的字符,不要與最左邊的單引號進行配對。

2.2.3 轉義字符

我們之前已經用過轉義字符了,你應該還記得“\n”,“n”本來是一個普通字符,加上反斜杠之后就表示換行了,類似的還有“\t”表示制表符(即按一下鍵盤上的Tab鍵)。問題來了,有時候我就想打印出“\n”這個字符而不是讓它換行那該怎么辦呢?很簡單,你在反斜杠前面再加一個反斜杠告訴Python這個反斜杠是普通字符,不表示轉義,我這么描述你可能會有點懵,來看一下下面的代碼就懂了:

print("我們知道"\n"表示換行")  # 輸出:我們知道"
                                                 "表示換行
print("我們知道"\\n"表示換行")  # 輸出:我們知道"\n"表示換行

以后我們學到文件操作的時候經常需要寫文件路徑,不巧的是Windows系統的文件路徑是使用反斜杠分隔的,如果你比較有耐心,在每一個反斜杠前面都手動加上一個反斜杠也是可以的。但為了效率,我還是建議使用在字符串前面加上一個“r”的寫法,即告訴Python字符串里的所有反斜杠都是普通字符而不是轉義字符。看一下例子,下面兩種寫法完全等價:

print("C:\\Users\\admin\\Documents\\WeChat Files\\Applet")
# 輸出:C:\Users\admin\Documents\WeChat Files\Applet
print(r"C:\Users\admin\Documents\WeChat Files\Applet")
# 輸出:C:\Users\admin\Documents\WeChat Files\Applet

2.2.4 字符串索引

一個字符串可以包含0個或多個字符,每一個字符也稱為元素。如果你拿到一個數據是字符串類型,但只需要其中的某個字符,我們可以通過元素位置去訪問字符。千萬注意,與我們的生活習慣不同,編程語言的位置基本上都是從0開始的,即第0個元素、第1個元素、第2個元素......。如果要訪問字符串某個位置的元素,可以使用半角的中括號,如下面的代碼所示:

my_str = "Of fice很幸運,她遇上了Python"
print(my_str[0])  # 輸出:O
print(my_str[10])  # 輸出:她

我想你應該看懂了,我們在字符串后面加上一個中括號,中括號里寫你要訪問第幾個元素,“my_str[0]”表示訪問字符串my_str的第0個元素,即字母“O”。你睡覺前可以偷偷從0開始數一下,看第10個元素是不是命中注定的“她”。

中括號里代表位置的數字,我們稱之為下標或者索引,所以我下面提到的“位置”“下標”“索引”其實都是同一個意思。注意,字符串里每一個字符都對應一個索引,包括標點符號和空格,所以一個長度為n的字符串的最大索引應該是n-1,如果超過索引的最大值,程序就會報“IndexError: string index out of range”的錯誤,你也可以自己用代碼驗證一下。

在寫程序的時候也不可能去數字符串的長度啊,萬一那個字符串有幾萬個字符怎么辦?不要擔心,我們可以通過len()函數獲取字符串長度,把變量名寫進括號里就會返回該字符串的長度了。另外你可以想一下,如果我們訪問的是字符串中0這個索引有沒有可能會報錯?有可能的,如果該字符串是一個空字符串,則不存在第0個元素。所謂空字符串就是沒有任何字符的字符串,下面的變量a、b、c、d、e都是空字符串,但f和g不是,因為f里面有一個空格,g里面有一個換行符,畢竟空格和換行符都是字符。代碼如下:

a = str()
b = ''
c = ""
d = ''''''
e = """"""
f = ' '
g = '\n'
print(len(a), len(b), len(c), len(d), len(e))  # 輸出:0 0 0 0 0
print(len(f), len(g))  # 輸出: 1 1

2.2.5 字符串切片

通過索引我們能訪問元素,但每訪問一個元素就寫一個位置是不是太麻煩了。如果你想一次訪問多個元素,我們可以使用切片,為了讓你不被“切片”這個高大上的詞嚇跑,我們先看看切片的用法。代碼如下:

my_str = "Of fice很幸運,她遇上了Python"
# 為了方便你數數,順便列出幾個字符的下標
# "Of fice很幸運,她遇上了Python"
# "012345 6 7 8 9"
print("my_str長度:", len(my_str))  # 輸出:my_str長度: 20
print(my_str[0:20:])  # 輸出:Of fice很幸運,她遇上了Python
print(my_str[6:9])  # 輸出:很幸運
print(my_str[6:])  # 輸出:很幸運,她遇上了Python
print(my_str[:9])  # 輸出:Of fice很幸運
print(my_str[6:-1])  # 輸出:很幸運,她遇上了Pytho
print(my_str[8:5:-1])  # 輸出:運幸很
print(my_str[0::2])  # 輸出:Ofc很運她上Pto

切片的用法很簡單,字符串的中括號里最多可以有三個參數,分別是開始位置、結束位置、步長,都是用半角冒號分隔。開始位置和結束位置都是下標,從0開始數,開始位置對應的元素包含在切片中,結束位置對應的元素不包含在切片中,比如說字符串my_str =“Off i ce很幸運,她遇上了Python”,索引6對應的是漢字“很”,索引9對應的是逗號“,”,而my_str[6:9]得到的是“很幸運”而不是“很幸運,”,這種現象我們稱之為“左閉右開”,“閉”是取得到,“開”是取不到(即取到的是前一個字符“運”)。步長的默認值是1,即每一個字符都取,如果指定步長為2,就會隔一個字符取一次,如果指定步長為3,那就隔兩個字符取一次,比如說my_str[0:20]、my_str[0:20:]、my_str[0:20:1]三種寫法效果是一樣的,都會取所有字符,而my_str[0:20:2]得到的結果是“Ofc很運她上Pto”,my_str[0:20:3]得到的結果是“Oi很,上yo”。

再說一下切片的三個參數的取值,可以分為3種情況。

(1)只要是整數都可以,包括正數和負數。對于正數的情況我們都理解了,符合我們的生活常識,就不再多說。負數就是從后往前取值,比如說my_str[6:-1],開始索引是6,結束索引是-1,表示從第6個索引開始一直取到倒數第一個索引,結果是“很幸運,她遇上了Pytho”,因為左閉右開的原則,最后一個字符“n”取不到。再舉一個例子,my_str[8:5:-1]的步長是-1,即從后往前取,索引8和5分別對應的字符是“運”和“e”,因為左閉右開,最終取到的是“運幸很”。

(2)三個參數都可以省略不寫。當不寫開始索引,則是從第0個索引開始;當不寫結束索引,則是取后面的全部字符;當不寫步長,則步長為1。舉個例子,my_str[6:]表示從索引6開始取完后面的所有字符,得到的結果是“很幸運,她遇上了Python”。當三個參數全都不寫,my_str[::]得到的效果與my_str一樣,即代表整個字符串。

(3)當索引超出范圍不會報錯,若取不到任何元素則返回空字符串。前面我們說了,通過索引訪問字符串,當索引對應的元素不存在則會報“string index out of range”的錯誤導致程序終止運行,比如說長度是20的my_str,你一意孤行要訪問第100個元素my_str[100]肯定會報錯的。但是如果你使用切片是不會報錯的,比如說my_str[6:100]會返回從第6個索引開始的后面的所有字符。如果是開始索引和結束索引都超出范圍也不會報錯,比如說my_str[99:100]會返回一個空字符串。

2.2.6 查詢元素

前面我們講了如何通過下標訪問字符串的元素,包括單個元素和多個元素,如果我想查詢某個元素在不在字符串里該怎么辦呢?str對象提供了index()和f i nd()兩個方法,用法是“對象.方法名()”,注意點和括號都是半角的,后面講到的其他方法中的標點符號也是類似的用法。示例代碼如下:

my_str = "Of fice很幸運,她遇上了Python"
print(my_str.index("很"))  # 輸出:6
print(my_str.index("很幸運"))  # 輸出:6
print(my_str. find("很"))  # 輸出:6
print(my_str. find("很幸運"))  # 輸出:6

觀察一下上面的代碼,我們主要得到兩個信息:一個是index()和f i nd()用法和結果一樣;另一個是當查詢多個字符的位置時它會返回第一個字符的位置。上面查詢的都是字符串里存在的字符,如果字符不存在,index()和f i nd()這兩個方法就不一樣了。代碼如下:

my_str = "Of fice很幸運,她遇上了Python"
print(my_str. find("愛"))  # 輸出:-1
print(my_str.index("愛"))  # 報錯:ValueError: substring not found

如果被查詢的字符不在字符串里,f i nd()會返回-1,而index則是直接報“ValueError:substring not found”的錯誤,程序也會因報錯導致終止執行。

2.2.7 拼接字符串

如果你有多個字符串,想要把它們合并為一個字符串,我們可以直接將二者相加。代碼如下:

my_str1 = "Of fice很幸運"
my_str2 = ","
my_str3 = "她遇上了Python"
my_str = my_str1 + my_str2 + my_str3
print(my_str)  # 輸出:Of fice很幸運,她遇上了Python

沒想到除了數字類型,字符串也是可以相加的吧?其實字符串還可以相乘,比如說有一個字符串“*-”,我想讓它重復出現10遍,則乘以10即可。代碼如下:

char = "*-" * 10
print(char)  # 輸出:*-*-*-*-*-*-*-*-*-*-

關于連接字符串,str對象還提供了一個join()方法,比如說,我想在字符串的每一個元素中間都加上其他元素,比如都加上一個空格,可以這么寫:

my_str = "Of fice很幸運,她遇上了Python"
my_str2 = " ".join(my_str)
print(my_str2)# 輸出:O f f i c e 很 幸 運 ,她 遇 上 了 P y t h o n

2.2.8 類型轉換

相加的對象如果是數字類型則會進行算術運算,如果是字符類型則會直接拼接字符串,如果是數字類型加上一個字符串類型會是什么樣的呢?程序會直接報錯的。如果你一定要嘗試,不妨對其中一個對象進行類型轉換,可以通過str()、int()、f l oat()分別把其他類型強轉成字符串、整型、浮點型。代碼如下:

num = 520
print(type(num), num)  # 輸出:<class 'int'> 520
# int類型轉換成str類型
num = str(num)
print(type(num), num)  # 輸出: <class 'str'> 520
# str類型轉換成int類型
num = int(num)
print(type(num), num)  # 輸出:<class 'int'> 520
# int類型轉換成 float類型
num_ float = float(num)
print(type(num_ float), num_ float)  # 輸出:<class ' float'> 520.0
# int類型轉換成 float類型
print(int(66.88))  # 輸出:66

使用這些方法可以隨意轉換以上三種類型,前提是長得像才能轉換成功,比如說字符串“520”可以轉換成int或f l oat類型,但是字符串“我很帥”就不能轉成int或f l oat,程序會報錯的,你可以鼓起勇氣試一下。為了防止把字符串轉換成int類型的時候報錯,轉換之前最好看一下它是不是可以轉換成int類型,我們可以通過字符串對象的isdigit()方法判斷,如果能轉成init則返回True,不能的話就會返回False,等以后我們學到了條件判斷就可以控制是否要轉換了,現在先記住這個方法。代碼如下:

my_str = "520"
is_digit = my_str.isdigit()
print(is_digit)  # 輸出:True
print("a1".isdigit())  # 輸出:False

另外,如果是f l oat類型數據轉換成int類型數據,則會丟掉小數部分只保留整數。以后我們學到的更多數據類型也可以使用這種方法進行轉換,但是能不能轉換還是取決于該種類型是否支持轉換。現在知道了類型轉換之后,可以試一下使用字符串參與算術運算了。代碼如下:

print(1 + 2)  # 輸出:3
print(1 + int("2"))  # 輸出:3
print( float("1") + float("2"))  # 輸出:3.0

2.2.9 替換字符串

如果你想更換字符串里的某些字符,可以通過str對象的replace()方法,該方法可以傳入三個參數,第一個是原字符串,第二個是目標字符串,第三個是替換次數,如果不寫替換次數就是全部替換,比如說我們把字符串my_str里的“遇”替換成“愛”,對比全部替換和替換一次的效果。代碼如下:

my_str = "Of fice很幸運,她遇上了Python,命運讓他們相遇"
new_str = my_str.replace("遇", "愛")
print(new_str)  # 輸出 Of fice很幸運,她愛上了Python,命運讓他們相愛
new_str2 = my_str.replace("遇", "愛", 1)
print(new_str2)  # 輸出:Of fice很幸運,她愛上了Python,命運讓他們相遇

注意替換字符串并不是改變原來的字符串,而是返回一個新的字符串。

2.2.10 大小寫轉換

如果你的字符串里有字母,可以使用str對象的lower()和upper()方法輕松進行大小寫轉換。代碼如下:

my_str = "Of fice很幸運,她遇上了Python"
new_str = my_str.lower()
print(new_str)  # 輸出:of fice很幸運,她遇上了python
print(my_str.upper())  # 輸出:OFFICE很幸運,她遇上了PYTHON

2.2.11 分割字符串

如果你想把字符串按照某個或某些字符進行分割,可以使用str對象的split()和rsplit()方法,這兩個方法用法一樣,區別是前者從左往右分割,后者是從右往左分割。split()和rsplit()的參數是一樣的,第一個參數是按什么字符串分割,第二個參數是最大分割次數,如果不指定最大分割次數則是分割所有。把字符串my_str按中文逗號進行分割,代碼如下:

my_str = "Of fice很幸運,她遇上了Python,命運讓他們相遇"
print(my_str.split(",", 1))
# 輸出:['Of fice很幸運', '她遇上了Python,命運讓他們相遇']
print(my_str.split(","))
# 輸出:['Of fice很幸運', '她遇上了Python', '命運讓他們相遇']
print(my_str.rsplit(",", 1))
# 輸出:['Of fice很幸運,她遇上了Python', '命運讓他們相遇']

可以看到分割后得到的是一個列表,我們將在下一節學習列表,先簡單知道列表是多個元素的集合,每個元素用半角逗號分開。my_str = “Off i ce很幸運,她遇上了Python,命運讓他們相遇”,my_str.split(“,”, 1)是指把字符串my_str按中文逗號從左邊分割1次,則得到“Off i ce很幸運”和“她遇上了Python,命運讓他們相遇”兩部分。因為my_str中有兩個中文逗號,所以如果不指定最大分割次數則應該得到三個部分。

2.2.12 格式化字符串

所謂的格式化字符串其實就是把一些變量填充到字符串中,讓字符串有一個統一的格式,有點像套模板。舉一個例子,有一個字符串是“{}很幸運,她遇上了{}”,大括號表示待填寫的數據,如果我有很多數據都按照這種形式填充,就相當于把這些數據格式化了。str()對象有一個format()方法用來格式化字符串,看一下代碼演示:

my_str = "{}很幸運,她遇上了{}"
name1 = "Of fice"
name2 = "Python"
print(my_str)  # 輸出:{}很幸運,她遇上了{}
print(my_str.format(name1, name2))  # 輸出:Of fice很幸運,她遇上了Python
print(my_str.format(name1))  # 報錯

看了上面的代碼,我想你應該已經理解什么是格式化了,簡單來說字符串中每個大括號都是一個坑,后面使用數據把那些坑填了。但是你要注意,如果待格式化的字符串有多個大括號,但你填充的數據數量不夠,程序是會報錯的。另外我們還注意到,format()方法里的數據是按從左到右的順序一個一個填進待格式化的字符串的大括號里的,如果不想按順序也是可以的,只要你在字符串的大括號里寫上使用format()里的第幾個參數,比如說第一個大括號和第三個大括號使用format()里的第1個參數,第二個大括號使用第0個參數,代碼如下:

my_str = "{1}也很幸運,他遇上了{0},所以{1}很開心"
print(my_str.format("Of fice", "Python"))
# 輸出:Python也很幸運,他遇上了Of fice,所以Python很開心

雖然可以指定位置,但是如果字符串很長,變量也很多,在看代碼的時候還要一個一個去數每個位置對應的變量是什么,就會很麻煩,但你只要在字符串前面加上一個字母“f”就可以指明哪個大括號被哪個變量填充了。代碼如下:

name1 = "Of fice"
name2 = "Python"
my_str = f"{name2}也很幸運,他遇上了{name1},所以{name2}很開心"
print(my_str)
# 輸出: Python也很幸運,他遇上了Of fice,所以Python很開心

這種在字符串前面加上“f”的寫法比format()方法顯得更加簡潔和直接,但是注意這種用法是Python3.6才開始支持的,即Python3.5和更早的版本不能用,所以從兼容性的角度來說,format()更好,因為即使在舊版本的Python環境代碼也能正常執行。

其實還有一種比較經典的寫法,幾乎所有的高級語言都支持,那就是使用占位符,Python中用“%”連接待格式化字符串和數據,代碼如下:

my_str = "%d年后,%s遇到了%s"
print(my_str % (5, "Of fice", "Python"))
# 輸出:5年后,Of fice遇到了Python

代碼中的%d代表用整型填充,%s代表用字符串填充,類似的還有%f,表示用浮點型填充,還有一些占位符就不列舉了,感興趣的朋友可以在網上搜一下。還需要補充的是%f是可以指定小數個數的,比如說“%.2f”(注意不要漏掉整數前面的小數點)就是填充的時候只保留兩位小數。如果想輸出“%”這個字符,那么就使用“%%”表示一個百分號。代碼如下:

print("%.2f是圓周率的近似值" % 3.1415926)  # 輸出:3.14是圓周率的近似值
print("增長比例高達%d%%" % 33.3)  # 輸出:增長比例高達33%
主站蜘蛛池模板: 上饶市| 油尖旺区| 衡山县| 黄陵县| 青海省| 富源县| 化州市| 新河县| 曲阜市| 乌拉特中旗| 错那县| 微博| 平乐县| 金川县| 肥城市| 镇安县| 永城市| 淮南市| 共和县| 突泉县| 万安县| 德清县| 漳平市| 安徽省| 原阳县| 安化县| 乐安县| 大关县| 望奎县| 芦溪县| 浦江县| 昭苏县| 古蔺县| 安陆市| 香河县| 洪雅县| 新泰市| 忻州市| 若尔盖县| 芦溪县| 沙坪坝区|