字串

April 9, 2022

Python 的字串有多種的表示方式。最基本的是實字表示方式,使用雙引號或單引號來包括字元序列:

>>> "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,結果會是個 stru 只是當初要推廣 Python 3.x,為了多一點與 Python 2 的相容性而加入;然而就現今 Python 3 的採用率來說,不用特別加上 u 了。

分享到 LinkedIn 分享到 Facebook 分享到 Twitter