Python 內建名為 "str" 的字串類別,提供許多便利的功能 (有個 "string" 的舊模組不應該使用)。字串常值可以用雙引號或單引號括住,但單引號較為常見。在單引號和雙引號的文字中,反斜線逸出會照常運作,例如: \n \ \"。雙引號的字串常值可以包含不含任何引號 (例如「我做錯」) 的單引號,同樣地的單引號字串可以含有雙引號。字串常值可以橫跨多行,但每一行的結尾都必須有反斜線「\」,以逸出新行。三引號內的字串文字「"」或「'」可以涵蓋多行文字。
Python 字串「不可變動」,代表這些字串在建立後即無法變更 (Java 字串也會使用這個不可變動的樣式)。由於字串無法變更,因此我們會建構「新」字串,以表示運算值。舉例來說,運算式 ('hello' + 'the'') 會擷取 2 個字串「hello」和「the」,然後建構一個新字串「hellothere」。
字串中的字元可透過標準 [ ] 語法存取,就像 Java 和 C++ 一樣,Python 也會使用從零開始的索引,因此如果 s 是「hello' s[1]」是「e」,如果索引超出字串的邊界,Python 就會引發錯誤。如果 Python 樣式 (與 Perl 不同) 無法判斷如何執行動作,便會暫停 Python 樣式,而不只是單純設定預設值。下方的實用的「slice」語法也能用來擷取字串中的任何子字串。len(string) 函式會傳回字串的長度。[ ] 語法和 len() 函式實際上可用於任何序列類型:字串、清單等。Python 會嘗試讓作業在不同類型中都能以一致的方式運作。Python 新手適用的程式碼:請勿使用「len」做為變數名稱,以免封鎖 len() 函式。「+」運算子可以串連兩個字串。請注意,在下列程式碼中,系統不會預先宣告變數,只要指派給這些變數即可。
s = 'hi' print(s[1]) ## i print(len(s)) ## 2 print(s + ' there') ## hi there
與 Java 不同,「+」不會自動將數字或其他型別轉換為字串格式。str() 函式會將值轉換為字串格式,以便與其他字串結合。
pi = 3.14 ##text = 'The value of pi is ' + pi ## NO, does not work text = 'The value of pi is ' + str(pi) ## yes
如為數字,標準運算子 +、/、* 就會照常運作。沒有 ++ 運算子,但 += 和 -= 等運算子也有效。若要計算整數除法,請使用 2 個斜線,例如 6 // 5 為 1
「print」函式通常會輸出一或多個 Python 項目,後面接著換行。「raw」字串常值的前置字串是「r」,會將所有字元傳遞到不使用特殊處理反斜線的方式,因此 r'x\nx' 評估為長度 4 字串 'x\nx'。「print」可能會使用多個引數來變更輸出內容的方式 (請參閱 Python.org 列印函式定義),例如將「end」設為「"」,避免在完成列印所有項目後停止輸出換行符號。
raw = r'this\t\n and that' # this\t\n and that print(raw) multi = """It was the best of times. It was the worst of times.""" # It was the best of times. # It was the worst of times. print(multi)
字串方法
以下列舉一些最常見的字串方法。方法與函式類似,但會在物件「上」執行。如果變數 s 是字串,則 s.lower() 程式碼會對該字串物件執行 low() 方法並傳回結果 (這樣在物件上執行方法,就是組成物件導向程式設計 (OOP) 的基本概念之一)。以下列舉幾個最常見的字串方法:
- s.lower(), s.upper() -- 會傳回字串的小寫或大寫版本
- s.strip() -- 會傳回從開頭和結尾移除空白字元的字串
- s.isalpha()/s.isdigit()/s.isspace()... -- 測試所有字串字元是否屬於各種字元類別
- s.startswith('other'), s.endswith('other') -- 測試字串的開頭或結尾是否為指定的其他字串
- s.find('other') -- 搜尋 s 中的指定其他字串 (非規則運算式),然後傳回第一個開始的索引 (如果找不到,則傳回 -1)
- s.replace('old', 'new') -- 會傳回字串,其中所有出現的「old」都已替換為「new」
- s.Split('delim') -- 會傳回以指定分隔符號分隔的子字串清單。分隔符號不是規則運算式,而是文字。'aaa,bbb,ccc'.split(',') -> ['aaa', 'bbb', 'ccc']。為了方便起見,s.split() (不含引數) 會在所有空白字元上分割。
- s.join(list) -- 對 split() 的反面,使用字串做為分隔符號,將指定清單中的元素彙整在一起,例如「---'.join(['aaa', 'bbb', 'ccc']) -> aaa---bbb---ccc
使用 Google 搜尋「Python str」後,系統會將您導向正式的 python.org 字串方法,其中會列出所有 str 方法。
Python 沒有獨立的字元類型。反之,例如 s[8] 的運算式會傳回包含該字元的字串-length-1。透過該 string-length-1,運算子 ==、<=、... 全都會照常運作,因此大部分情況下,您不需要瞭解 Python 沒有獨立的純量「char」類型。
字串配量
想要參照序列的子部分,通常是字串和清單,而「切片」語法是相當實用的方法。配量 [start:end] 是指元素的開頭和延伸,不會包含結尾元素。假設我們有 =「Hello」
- s[1:4] 為「ell」 -- 從索引 1 開始的字元,擴充為不含索引 4 的字元
- s[1:] 為「ello」,省略任一索引預設為字串的開頭或結尾
- s[:] 是「Hello」 -- 省略兩者一律會提供給我們完整內容的副本 (這是將序列複製如字串或清單的 Python 方法)
- s[1:100] 是「ello」 -- 過大的索引會截斷至字串長度
標準的索引號碼從零開始,可讓您輕鬆存取接近字串開頭的字元。或者,Python 使用負數來輕鬆存取字串結尾的字元:s[-1] 是最後一個字元「o」,s[-2] 是「l」到下一個字元,依此類推。從字串尾端起算的負索引數:
- s[-1] 是「o」 -- 最後一個字元 (從最後 1 個字元開始)
- s[-4] 是「e」 -- 第 4 次
- s[:-3] 是「他」,最後 3 個字元,最多不包含最後 3 個字元。
- s[-3:] 是「llo」,從結尾的第 3 個字元開始,延伸至字串結尾。
這是針對任何索引 n (s[:n] + s[n:] == s
) 的切片細膩。這也適用於 n 負數或邊界。或者,其他方式 s[:n] 和 s[n:] 一律會將字串分區為兩個字串部分,並保留所有字元。您將在清單部分看到,切片也能與清單搭配使用。
字串格式
Python 可採取的其中一個簡單做法,就是自動將物件轉換為適合列印的字串。有兩個內建方法可以做到這一點,也就是格式化字串常值 (也稱為「f 字串」) 和叫用 str.format()。
格式化字串常值
您經常會在下列情況中看到格式化字串常值:
value = 2.791514 print(f'approximate value = {value:.2f}') # approximate value = 2.79 car = {'tires':4, 'doors':2} print(f'car = {car}') # car = {'tires': 4, 'doors': 2}
格式化常值字串的前置字串是「f」(例如原始字串使用的「r」前置字串)。大括號「{}」外的任何文字都會直接輸出。「{}」中包含的運算式是以格式規格所述的格式規格列印出來。格式規格中有許多繁瑣的功能,包括截斷和轉換成科學記號,以及靠左/右/置中對齊。
如果您想輸出物件表格,並且想要代表不同物件屬性的資料欄對齊方式,f 字串就很實用
address_book = [{'name':'N.X.', 'addr':'15 Jones St', 'bonus': 70}, {'name':'J.P.', 'addr':'1005 5th St', 'bonus': 400}, {'name':'A.A.', 'addr':'200001 Bdwy', 'bonus': 5},] for person in address_book: print(f'{person["name"]:8} || {person["addr"]:20} || {person["bonus"]:>5}') # N.X. || 15 Jones St || 70 # J.P. || 1005 5th St || 400 # A.A. || 200001 Bdwy || 5
字串百分比
Python 也具有類似 printf() 的舊版功能,可組合字串。% 運算子會接受左側的 printf 類型格式字串 (%d int、%s 字串、%f/%g 浮點),以及右側元組中的相符值 (元組是由以半形逗號分隔的值組成,通常在括號中組成):
# % operator text = "%d little pigs come out, or I'll %s, and I'll %s, and I'll blow your %s down." % (3, 'huff', 'puff', 'house')
上面這一行的長度很長,假設您想要分行將其分割成不同的行。您無法按照在其他語言中的 '%' 之後分隔這一行,因為根據預設,Python 會將每一行視為個別的陳述式 (因此在加號上,就不需要在每一行輸入分號)。若要修正此問題,請將整個運算式包在一組外括號內,這樣運算式即可橫跨多行。這項跨行程式碼技巧適用於下列各種分組結構:( )、[ ]、{ }。
# Add parentheses to make the long line work: text = ( "%d little pigs come out, or I'll %s, and I'll %s, and I'll blow your %s down." % (3, 'huff', 'puff', 'house'))
這樣好了,但線條還是很長。Python 能讓您將一行分割為多個片段,然後進一步自動串連。因此,為了讓這行程式碼更短,我們可以這樣做:
# Split the line into chunks, which are concatenated automatically by Python text = ( "%d little pigs come out, " "or I'll %s, and I'll %s, " "and I'll blow your %s down." % (3, 'huff', 'puff', 'house'))
字串 (萬國碼 (Unicode) 與位元組)
一般 Python 字串是 Unicode。
Python 也支援由純位元組組成的字串 (在字串常值前方以「b」符號表示),例如:
> byte_string = b'A byte string' > byte_string b'A byte string'
萬國碼 (Unicode) 字串是位元組字串中的不同物件類型,但只要傳遞任一類型字串,各種程式庫 (例如規則運算式) 即可正常運作。
如要將一般 Python 字串轉換為位元組,請對字串呼叫 Encode() 方法。順帶一提,位元組字串 decode() 方法會將已編碼的純位元組轉換為萬國碼 (Unicode) 字串:
> ustring = 'A unicode \u018e string \xf1' > b = ustring.encode('utf-8') > b b'A unicode \xc6\x8e string \xc3\xb1' ## bytes of utf-8 encoding. Note the b-prefix. > t = b.decode('utf-8') ## Convert bytes back to a unicode string > t == ustring ## It's the same as the original, yay!True
在檔案閱讀部分中,示範的是如何開啟含有某些編碼的文字檔,以及讀取萬國碼 (Unicode) 字串。
If 陳述式
Python 不會使用 { } 來包住 if/loops/function 的程式碼區塊。而是改用冒號 (:) 和縮排/空白字元將陳述式分組。if 的布林值測試不需要在括號中 (與 C++/Java 有大差異),並且可以包含 *elif* 和 *else* 子句 (記憶:「elif」一詞的長度與「else」這個字的長度相同)。
任何值都可以用做 if-test。所有「零」值都會計為 false:無、0、空白字串、空白清單、空白字典。還有一個包含兩個值的布林值類型:True 和 False (轉換為 int,兩者為 1 和 0)。Python 的比較運算操作如下:==、!=、<、<=、>、>=。與 Java 和 C 不同,== 經過超載,可與字串正確搭配使用。布林運算子為「和」*、「或」*、*not* (Python 不使用 C-style && || !)。以下是程式碼在一天當中可能會提供飲料建議的程式碼外觀。請注意,gan/else 陳述式的每個區塊都以 : 開頭,且陳述式會以縮排的方式分組:
if time_hour >= 0 and time_hour <= 24: print('Suggesting a drink option...') if mood == 'sleepy' and time_hour < 10: print('coffee') elif mood == 'thirsty' or time_hour < 2: print('lemonade') else: print('water')
我發現在上述程式碼類型中輸入時,省略「:」是我最常見的語法錯誤,因為相較於我的 C++/Java 習慣,這會是另一件事。此外,請勿將布林值測試加上括號,也就是 C/Java 的習慣。如果程式碼很短,您可以將程式碼放在同一行的「:」之後,例如:函式、迴圈等 (這也適用於函式、迴圈等),雖然有些人認為分隔不同行的內容比較容易理解。
if time_hour < 10: print('coffee') else: print('water')
運動:string1.py
如要練習本節所述的內容,請嘗試透過基本練習中的 string1.py 練習。