目錄
一、說明
1.1 函數原型
static str.maketrans(x[, y[, z])
此靜態方法返回一個可供 str.translate() 使用的轉換對照表。
注意:Python3.4+ 已移除 string.maketrans(),由內建函數 bytearray.maketrans()、bytes.maketrans()、str.maketrans() 替代。
1.2 dict 操作
若只輸入1個參數 x,則 x 必須是一個將 Unicode 碼位序號 (int) 或字符 (長度爲1的 string) 映射到 Unicode 碼位序號、(任意長度的)字符串或 None 的字典。 注意,若輸入字典 x 的 key 爲字符,則輸出字典的 key 會被轉換爲 Unicode 碼位序號。例如:
>>> dict0 = {'a': 1, 'b': 2, 'c': 3} # key 爲字符 (長度爲1的 string)
>>> str.maketrans(dict0) # ord('a')=97, ord('b')=98, ord('c')=99
{97: 1, 98: 2, 99: 3}
# ---------------------------------------------------------------------
>>> dict1 = {10: 1, 11: 2, 12: 3} # key 爲 Unicode 碼位序號 (int)
>>> str.maketrans(dict1) # key 類型爲 int 輸出不變
{10: 1, 11: 2, 12: 3}
# ---------------------------------------------------------------------
>>> dict2 = {'n': None, '0': None, 0: None} # key 混合類型
>>> str.maketrans(dict2) # ord('n')=110, ord('0')=48
{110: None, 48: None, 0: None}
但該操作並不常用。
1.3 string 操作
若輸入2個參數,則二者必須爲 長度相等且一一對應的字符串,此時該方法用於 創建字符映射的轉換表。其中 x 是待轉換字符串,y 是轉換目標字符串。該方法輸出一個字典, 其中 x 中每個字符將被映射到 y 中相同位置的字符。例如:
>>> in_table = 'ab'
>>> out_table = '12'
>>> trans_table = str.maketrans(in_table, out_table)
>>> trans_table
{97: 49, 98: 50}
輸出字典中,key 是 x 中字符的 Unicode 碼位序號, value 是 y 中字符的 Unicode 碼位序號,驗證如下:
>>> ord('a')
97
>>> ord('b')
98
>>> ord('1')
49
>>> ord('2')
50
如果 x 中存在重複的字符,則自動選用索引最大的字符來映射:
>>> in_table = 'abb'
>>> out_table = '123' # ord('1')=49, ord('1')=50, ord('1')=51
>>> trans_table = str.maketrans(in_table, out_table)
>>> trans_table # 可見對於重複的 key, 選用的了索引更大(位置更靠後)的
{97: 49, 98: 51}
此外,若輸入第3個參數 z,則它必須是一個字符串,其中的字符將在輸出字典中被映射到 None。例如:
>>> in_table = 'ab'
>>> out_table = '12'
>>> other_table = 'yz' # ord('y')=121, ord('z')=122
>>> trans_table = str.maketrans(in_table, out_table, other_table)
>>> trans_table
{97: 49, 98: 50, 121: None, 122: None}
二、典例 —— 字符串解密
該例子改編自 Python Challenge-2。給出一個句子,解密方法是:讀取每個字母的 ASCII 碼 +2 後的字母組成的句子:
g fmnc wms bgblr rpylqjyrc gr zw fylb.
根據該轉換關係,很容易想到利用內建函數 ord() 將字母轉換成 ASCII 碼、chr() 將相對應的 ASCII 碼轉化爲字母,然後依次遍歷字符串中的字符轉化:
>>> text = """g fmnc wms bgblr rpylqjyrc gr zw fylb."""
>>> def solution1(text):
result = ""
for each in text:
if ord(each) >= ord('a') and ord(each) <= ord('z'):
# 因爲 ord('y')=121, ord('z')=122, ord('{')=123, ord('|')=124
# 故應確保 'y' 和 'z' 的 ASCII 碼 +2 後應循環恢復爲 'a' 和 'b'
result += chr((ord(each) + 2 - ord('a')) % 26 + ord('a'))
else:
result += each
print(result)
>>> solution1(text) # 轉換解碼
i hope you didnt translate it by hand.
但實際上,Python 提供了更爲便捷的解決方式 —— 使用 str.maketrans() + str.translate() 方法,如下所示:
import string
text = """g fmnc wms bgblr rpylqjyrc gr zw fylb."""
>>> def solution2(text):
table = str.maketrans(
string.ascii_lowercase, # 26 個小寫字母 a-z
string.ascii_lowercase[2:] + string.ascii_lowercase[:2]) # c-z 接上 a-b
print(table)
print(text.translate(table))
>>> solution2(text)
{97: 99, 98: 100, 99: 101, 100: 102, 101: 103, 102: 104, 103: 105, 104: 106, 105: 107, 106: 108, 107: 109, 108: 110, 109: 111, 110: 112, 111: 113, 112: 114, 113: 115, 114: 116, 115: 117, 116: 118, 117: 119, 118: 120, 119: 121, 120: 122, 121: 97, 122: 98}
i hope you didnt translate it by hand.
可見,輸出 dict 中均爲 Unicode 碼位序號構成的 key:value 對。其中,key 是 26 個小寫字母 a-z 的 Unicode 碼位序號,value 則是 key 的 Unicode 碼位序號 +2,對應 b-z 接上 a-b 這 26 個字母 (相當於右循環移2步)。
最後,使用 string.translate() 方法,根據映射規則表 table,將密語 text “翻譯/轉換” 爲解密語 string 。
三、附錄 —— Unicode 碼速查表
上表來自百度百科。
參考文獻
http://www.pythonchallenge.com/pc/def/map.html
https://www.runoob.com/python3/python3-string-maketrans.html
https://docs.python.org/zh-cn/3.6/library/stdtypes.html?highlight=maketrans#str.maketrans
https://docs.python.org/zh-cn/3.6/library/stdtypes.html?highlight=maketrans#str.translate