字串
April 9, 2022Python 的字串有多種的表示方式。最基本的是實字表示方式,使用雙引號或單引號來包括字元序列:
>>> "Justin"
'Justin'
>>> 'Justin'
'Justin'
>>> "Just'in"
"Just'in"
>>> 'Just"in'
'Just"in'
>>> 'Just' 'in'
'Justin'
字串表示
單引號或雙引號的字串表示,可以交替使用,就像上例中,若要在字串中包括單引號,則使用雙引號包括字元序列,反之亦然。如果有兩個連續的字串實字,會自動將之結合為一個字串。
撰寫字串致力於簡潔易讀,字串中若包括 \,某些情況下不用特別處理,會自動轉換為 \\,因此可以直接如下撰寫字串:
>>> 'c:\workspace'
'c:\\workspace'
>>> 'c:\\workspace'
'c:\\workspace'
>>>
直接撰寫 'c:\workspace' 就如同自行撰寫 'c:\\workspace',前者在撰寫與可讀性上都比較方便。\\ 是轉義(Escape)字串表示,來看一些常用的轉義(Escape)字串表示:
\\:反斜線。\':單引號 ‘。\":雙引號 “。\ooo:以 8 進位數字 ooo 表示字元碼點(Code point),最多三位數,例如'\101'表示字串'A'。\xhh:以 16 進位數字 hh 表示字元碼點,例如'\x41'表示字串'A'。\uhhhh:以 16 進位數字 hhhh 表示字元碼點,例如'\u54C8\u56C9'表示'哈囉'。\Uhhhhhhhh:以 16 進位數字 hhhhhhhh 表示字元碼點,例如'\U000054C8\U000056C9'表示'哈囉','\U0001D11E'表示高音譜記號。\0:空字元。\n:換行。\r:歸位。\t:Tab。
在一些程式語言中(例如 Java、JavaScript),字串轉義表示會有碼元(Code unit)、代理對(Surrogate pair)之類的問題,Python 3.x 完全支援 Unicode,只需選擇適當的格式來表示碼點。
因此,想要以字串表示 \t 這類文字,必須撰寫 '\\t' 來表示,這有些不方便,這時你可以使用原始字串(Raw String)表示,只要在字串前加上 r 即可。例如:
>>> print('\t')
>>> print('\\t')
\t
>>> print(r'\t')
\t
>>> print('c:\\workspace')
c:\workspace
>>> print(r'c:\\workspace')
c:\\workspace
>>> '\t'
'\t'
>>> r'\t'
'\\t'
>>> 'c:\\workspace'
'c:\\workspace'
>>> r'c:\\workspace'
'c:\\\\workspace'
>>>
如果你的字串內容必須跨越數行,可以使用三重引號。例如:
>>> '''Justin is caterpillar!
... caterpillar is Justin!'''
'Justin is caterpillar!\n caterpillar is Justin!'
>>> text = '''Justin is caterpillar!
... caterpillar is Justin!'''
>>> print(text)
Justin is caterpillar!
caterpillar is Justin!
>>>
在三重引號之間輸入任何內容,則最後的字串就照單全收,包括換行、縮排等。
字串操作
如果想知道字串的長度,則可以使用 len 函式。例如:
>>> text = 'Justin'
>>> len(text)
6
>>>
可以使用 for 迴圈逐一取出字串中的字元:
>>> for c in 'Justin':
... print(c, end='-')
...
J-u-s-t-i-n->>>
或者是使用 in 運算子測試某個字串是否在原字串中:
>>> 'Just' in 'Justin'
True
>>>
可以使用 + 運算子來串接字串,使用 * 可以重複字串:
>>> text1 = 'Just'
>>> text2 = 'in'
>>> text1 + text2
'Justin'
>>> text1 * 10
'JustJustJustJustJustJustJustJustJustJust'
>>>
字串是不可變動的(Immutable),+ 實際會產生新字串。
在強弱型別的光譜中,Python 比較偏強型別,型態較不能自行轉換,例如 Python,不能混合字串與數字進行 + 運算,你得自己將數字轉為字串,才可以進行字串串接:
>>> 'score: ' + 90
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't convert 'int' object to str implicitly
>>> 'score: ' + str(90)
'score: 90'
>>>
如上例所示,可以使用 str 將數值轉換為字串。
字串是由字元序列所組成,如果想取得字串中某個字元,可以使用 [] 指定索引,索引從 0 開始。例如:
>>> name = 'Justin'
>>> name[0]
'J'
>>> name[1]
'u'
>>> name[-1]
'n'
>>>
索引可指定正值,還可以指定負值,實際上了解索引意義的開發人員,都知道索引其實就是相對第一個元素的偏移值,在 Python 中,正值索引就是指正偏移值,負值索引就是負偏移值,也就是 -1 索引就是倒數第一個元素,-2 索引就是倒數第二個元素。
[] 運算子還可以進行切片(Slice)運算。例如:
>>> name[0:3]
'Jus'
>>> name[3:]
'tin'
>>> name[:4]
'Just'
>>> name[:-1]
'Justi'
>>> name[-5:-1]
'usti'
>>>
上例中指出了切片運算,可以指定起始索引(包括)與結尾索引(不包括)來切出子字串。如果只指定起始索引,不指定結尾索引,則表示切出從起始索引至字串結束間的子字串。如果只指定結尾索引,不指定起始索引,則表示切出從 0 索引至(不包括)結尾索引間的子字串。起始索引與結尾索引都可以指定負值。([:] 則是作淺層複製,只不過對字串這種不可變動的物件沒有實質意義)
切片運算的另一個形式是 [i:j:k],意思是切出起始索引 i 與結尾索引 j(不包括)之間,每隔 k 元素的內容。例如:
>>> name[0:4:2]
'Js'
>>> name[2::2]
'si'
>>> name[:5:2]
'Jsi'
>>> name[::2]
'Jsi'
>>> name[::-1]
'nitsuJ'
>>>
當間隔指定為正時,表示正偏移每 k 個取出元素,間隔指定為負時,表示負偏移每 k個取出元素。[::-1] 表示從索引 0 至結尾,以負偏移 1 方式取得字串,結果就是反轉字串。
字串碼點/編碼
如果想知道某個字元的碼點並以整數表示,可以使用 ord 函式,使用 chr 可以將指定的碼點整數表示轉換為字元:
>>> ord('元')
20803
>>> chr(20803)
'元'
>>>
從Python 3以後,每個字串都包含了 Unicode 字元,字串都是 str 實例,如果想將字串轉為指定的位元組編碼,可以使用 encode 方法,這會取得 bytes 實例,如果有個 bytes 實例,也可以使用 decode 方法指定編碼取得 str 實例:
>>> '元'.encode('big5')
b'\xa4\xb8'
>>> '元'.encode('utf-8')
b'\xe5\x85\x83'
>>> '元'.encode('big5').decode('big5')
'元'
>>>
搞不清楚誰可以用 encode 而誰可以用 decode 嗎?'\xe5\x85\x83' 這樣的資訊,人類不容易理解,編碼就是將可理解的東西,變為不容易理解的資訊(encode),反之將不易理解的資訊,變為可理解的東西就是解碼(decode)。
在 REPL 顯示結果可以看到,可以在字串前加上 b 來建立 bytes,這是從 Python 3.3 以後開始支援的語法,也可以在字串前加上 u,結果會是個 str,u 只是當初要推廣 Python 3.x,為了多一點與 Python 2 的相容性而加入;然而就現今 Python 3 的採用率來說,不用特別加上 u 了。


