跳到內容

字串 String

字串就是一段文字。前面已經一直在用它,這一章專門看字串能做哪些事:拆開、拼接、搜尋、比大小,以及把它排得整整齊齊。

字串裡的每個字都有索引,可以像串列一樣用索引和切片來取。len() 算的是有幾個字:

word = "Python"
print(word[0])
print(word[-1])
print(word[0:3])
print(len(word))

切片一樣可以用第三個數字當間隔。[::-1] 就是把字串反過來,是很常見的小技巧:

word = "Python"
print(word[::-1])

字串內建很多好用的方法,這裡是幾個最常見的:

text = " Hello, World "
print(text.upper())
print(text.strip())
print(text.replace("World", "Python"))
  • upper() / lower():全部轉大寫/小寫。
  • strip():去掉頭尾的空白。
  • replace(舊, 新):把字串裡的某段換成別的。

這幾個方法有個共通點:都是回傳一個新的字串,原本的字串不會被改到(字串和元組一樣,建立後不能直接修改)。

split() 依你指定的符號把字串切成一個串列;join() 相反,把串列裡的字串用某個符號串成一整段:

sentence = "蘋果,香蕉,橘子"
fruits = sentence.split(",")
print(fruits)
joined = "、".join(fruits)
print(joined)

處理一行用逗號隔開的資料時,這兩個方法幾乎天天用到。

想知道某段文字在不在、在哪裡、出現幾次:

email = "user@example.com"
print("@" in email)
print(email.find("@"))
print(email.count("e"))
  • x in 字串:檢查有沒有,回傳 True 或 False。
  • find(x):回傳第一次出現的索引(找不到會回傳 -1)。
  • count(x):數出現幾次。

有一組方法用來檢查字串「是不是某種樣子」,回傳 True 或 False,常用在檢查使用者輸入(例如密碼、帳號):

print("abc123".isalnum())
print("12345".isdigit())
print("Hello".isupper())
print("HELLO".isupper())
print("hello world".title())
  • isdigit():是不是全部都是數字。
  • isalnum():是不是全部都是文字或數字(沒有符號、空白)。
  • isupper() / islower():是不是全大寫/全小寫。
  • title():把每個單字的字首轉大寫。

rjust() 把字串靠右、補到指定寬度,第二個參數是拿什麼來補(預設是空白)。zfill() 則專門在左邊補 0,常用來排數字:

print("7".rjust(3))
print("7".rjust(3, "0"))
print("42".zfill(5))

每個字元在電腦裡都對應一個數字編號,Python 用的是 Unicode。這套編碼收錄了世界上各種文字,英文和數字的部分沿用更早的 ASCII,所以大寫 A 是 65;中文字也有自己的編號,中 是 20013。ord() 把字元轉成它的編號,chr() 反過來把編號轉回字元:

print(ord("A"))
print(chr(65))
print(ord("中"))
print(chr(ord("a") + 1))

chr(ord("a") + 1) 先拿到 a 的編號、加 1、再轉回字元,就得到 b。處理「下一個字母」這類問題時會用到。

每個字元都對應一個編號,所以字元可以直接比大小。選擇敘述那章用來比數字的 <、>、==,拿來比字元也一樣能用,比的就是 ord() 拿到的那個編號:

print("a" < "b")
print(ord("a"), ord("b"))
print("Z" < "a")
print(ord("Z"), ord("a"))

"a" < "b" 是 True,因為 97 小於 98。a 到 z 的編號是連號排下來的,所以比編號的結果剛好就是字母順序。

"Z" < "a" 也是 True,這個要小心:大寫字母的編號是 65 到 90,小寫是 97 到 122,整批大寫都排在小寫前面。

字串也能直接比,比法是一個字元一個字元、從左邊往右比,第一個不一樣的字元就決定結果,後面的完全不看。英文字典排單字就是這樣排的,所以叫字典順序:

print("apple" < "banana")
print("apple" < "apply")
print("app" < "apple")

三行剛好是三種情況:

  • "apple" < "banana":第一個字元 a 和 b 就不一樣,a 比較小,到這裡就決定了,後面幾個字元根本沒比到。
  • "apple" < "apply":前四個字元一模一樣,比到第五個 e(101)和 y(121)才有差別。
  • "app" < "apple":比到 app 沒字了都還一樣,這時候短的算小,就像字典裡 app 排在 apple 前面。

串列的 sort() 和 sorted() 排字串時,用的就是這套規則。

大小寫和數字是最容易踩到的兩個:

print("Zebra" < "apple")
print("Zebra".lower() < "apple".lower())
print("10" < "9")
print(int("10") < int("9"))

"Zebra" < "apple" 是 True。這跟字母順序無關,純粹是大寫的編號比小寫小。想照平常的字母順序比,先用 lower() 把兩邊都轉成小寫再比。

"10" < "9" 也是 True,因為比的是字元 1(49)和 9(57),不是數字 10 和 9。要比數字就得先用 int() 轉過去。學號、檔名這類「數字存成字串」的資料,排出來會變成 1、10、2、3,多半就是踩到這個。

中文字也有編號,所以中文字串一樣比得動,但比出來是 Unicode 的編號順序,既不是筆畫也不是注音。要照中文習慣排,得自己指定 key。

想把變數的值嵌進一段文字,直覺的做法是用 + 把字串接起來。但 Python 的文字不能直接和數字相加,"你今年 " + age 會直接出錯,得先用 str() 把數字轉成字串,而且片段一多,引號和加號排起來也很難讀。f-string 就是來解決這件事的(Python 3.6 以後才有):在字串前面加一個 f,把變數用大括號 {} 包起來放進字串,值會自動帶進去,型別轉換也不用煩惱。下面兩行印出同一句話,比較看看哪個好讀:

name = "小美"
age = 20
print("你好," + name + ",你今年 " + str(age) + " 歲。")
print(f"你好,{name},你今年 {age} 歲。")

在大括號裡,變數後面加冒號還能指定格式,最常用的是控制小數位數:

price = 1234.5678
print(f"{price:.2f}")
print(f"{price:,.2f}")

:.2f 是「保留兩位小數」,:,.2f 再加上千分位逗號,很適合印金額。

在冒號後面放方向和寬度,可以把文字補到固定的寬度:< 靠左、> 靠右、^ 置中,後面的數字是欄寬,表示這一格總共佔幾個字元,內容不夠長就用空白補滿。三個名字長短不一,補滿之後直行就對齊了:

a = "Ann"
b = "Bob"
c = "Cathy"
print(f"|{a:<8}|{a:>8}|{a:^8}|")
print(f"|{b:<8}|{b:>8}|{b:^8}|")
print(f"|{c:<8}|{c:>8}|{c:^8}|")

(這裡用英文示範,因為欄寬算的是「字元數」,而中文字比英文寬,中英混排時對齊會有點跑掉。)

數字格式和對齊也能同時用,但擺放順序是固定的:先寫對齊和欄寬,再千分位,最後小數位數,像 {total:>12,.2f}。冒號後面其實是一整段「格式規格」,Python 按位置一段一段解讀,擺錯(例如 {total:.2f>12})會直接出錯:

price = 1234.5
total = 98765.432
print(f"|{price:>12,.2f}|")
print(f"|{total:>12,.2f}|")

格式規格還有更多花樣(補 0、帶正負號、百分比……),需要時可以查官方文件的格式規格說明。

你在別人的程式裡可能會看到另外兩種比較舊的格式化寫法,% 和 .format():

name = "小明"
age = 18
print("%s 今年 %d 歲" % (name, age))
print("{} 今年 {} 歲".format(name, age))

三種寫法做的事一樣。知道它們長什麼樣就好,自己寫的時候,用 f-string 通常最直覺、最好讀。

v0.9.1 (c924b5b)