最近面試的時候遇到一個頗容易,但我卻一時三刻不能解答的問題,就是在 Python 裡如何把英文字母以數字的形式表達?
譬如說我們有像 Excel 試算表的數據,以英文字母代表列(Column): {'A1': 10, 'B1': 30, 'C3': 20}
。我們如何把 A1 轉換成 (1, 1),B1 轉換成 (2, 1) 等座標,方便我們使用數字索引(index)?
ASCII 與英文字母
如果您曾經學習過一些編程,或者會聽說過 ASCII (美國資訊交換標準代碼)這一個概念。簡單來說,ASCII 是一個國際認受的字元(character)索引(index)。
上圖顯示 ASCII 索引表的某些數值。留意左邊的數值(46-109)是一個索引(index),而右邊是該索引所指的符號/字元。
比方說,在 ASCII 索引表的第 63 個符號是「?」。
我們注意到 ASCII 索引表的第 65 個符號是大寫「A」,而第 97 個符號是小寫「a」。而其他英文字母則以順序排列在 66-90 (大寫)和 98-122(小寫)。
因此,我們只需要在 ASCII 表找到將所需的英文字母,例如「p」,便可以把所有英文字母以數字形式排列。
ord():英文字母到數字
print('a 的 ASCII 索引是', ord('a'))
print('A 的 ASCII 索引是', ord('A'))
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
要達到上面提及的要求,在 Python 裡,我們可以使用內置的功能 ord()
獲取一個單字的 ASCII 索引。
如上面所示,我們輸入 ord('a')
以後,會輸出 97,即英文字母 a 的 ASCII 索引。
留意 ‘a’ (小寫)和 ‘A’ (大寫)的 ASCII 索引不同,因此我們在處理大小寫時需要小心。
如果我們需要找到一串英文字母的 ASCII 索引,該如何辦?
多於一個英文字母的 ord()
my_str = 'PythonViz'
[x + ' 的 ASCII 代碼是 ' + str(ord(x)) for x in my_str]
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
我們當然使用 Python 的好朋友 List Comprehension (按此了解更多)去處理這個情況。如上圖所示,我們可以直接使用 ord(x) for x in my_str
的語法,揉合 List Comprehension 去獲取多個英文字母的 ASCII 索引。
把英文字母排序
回到我們原本的問題:如何知道英文字母的排列(如 A -> 1, B -> 2 …)?
我們最終希望寫出一個 Python 功能。這裡我們先做一些假設:
- 大寫小寫不重要:英文字母 “P” 和 “p” 的排序是一樣
- 英文字母從 1 開始:A 代表 1,B 代表 2,如此類推
- 輸入只有 1 個字母:如輸入 “ab”,程式會顯示錯誤
- 輸入不是字母時:如輸入 “1”,程式會顯示錯誤
def alphabet_index(alphabet:str):
if len(alphabet) > 1:
raise NotImplementedError('請輸入 1 個單字的英文字母')
elif alphabet.isupper():
return ord(alphabet) - ord('A') + 1
elif alphabet.islower():
return ord(alphabet) - ord('a') + 1
else:
raise NotImplementedError('"' + alphabet + '" 並不是英文字母')
# 現在我們試一下不同情況的回傳
for x in ['a','B','1','abcd']:
try:
print('輸入:', x, '\n輸出:', alphabet_index(x),'\n')
except Exception as e:
print('輸入:', x, '\n輸出:', e,'\n')
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
我們在上面編寫了一個簡單的 Python 功能 alphabet_index()
處理我們上述的要求。這個編程的結構如下:
if len(alphabet) > 1
: 如果我們輸入多於一個字元(例如 ‘abcd’),要求用家改為輸入單一英文字母elif alphabet.isupper()
: 如果用家輸入一個大寫英文字母,回傳這個字母與 “A” 的 ASCII 位置分別elif alphabet.islower()
: 如果用家輸入一個大寫英文字母,回傳這個字母與 “a” 的 ASCII 位置分別else
: 如果用家不是輸入一個英文字母,要求用家改為輸入單一英文字母
在我們的輸出可見我們成功回傳 “B” 為 2,並正確地要求用家重新輸入 “1” 和 “abcd”。
將 A1,B2 等換成座標
最後一個 ord()
功能的是把 A1、B2 格式的座標轉換成 (1,1)、(2,2) 的格式,方便我們使用數字索引進行計算。
如上圖所示,假如我們使用一個字典(dictionary)儲存這個座標的資料,會是 {'A1': 10, 'B2': 12, 'C4': 15, 'D2': 11}
。我們能否把座標變成 (1,1) 的格式?
coordinates = {'A1': 10, 'B2': 12, 'C4': 15, 'D2': 11}
{(ord(k[0])-ord('A')+1,int(k[1])): v for k, v in coordinates.items()}
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
我們可以直接使用 ord(k[0]) - ord('A') + 1
把存於字典的座標 ‘A’ 轉換成 1,‘B’ 轉換成 2 等等。如果我們想在輸出前進一步核實座標,可以考慮重用我們剛才的 alphabet_index()
自訂功能:
def alphabet_index(alphabet:str):
if len(alphabet) > 1:
raise NotImplementedError('請輸入 1 個單字的英文字母')
elif alphabet.isupper():
return ord(alphabet) - ord('A') + 1
elif alphabet.islower():
return ord(alphabet) - ord('a') + 1
else:
raise NotImplementedError('"' + alphabet + '" 並不是英文字母')
coordinates = {'A1': 10, 'b2': 12, 'C4': 15, 'd2': 11}
print({(alphabet_index(k[0]),int(k[1])): v for k, v in coordinates.items()})
coordinates = {'A1': 10, '#2': 12, 'C4': 15, 'd2': 11}
print({(alphabet_index(k[0]),int(k[1])): v for k, v in coordinates.items()})
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
留意我們把 “B” 和 “D” 換成小寫亦能回傳正確的座標。而假如我們輸入了無效的座標(例如 “#1″),亦會回傳錯誤(Error)。
chr():數字到英文字母
學會了 ord()
這一個功能後,chr()
就只不過是還原 ord()
的動作而已。簡單來說,chr()
是將 ASCII 索引(index)轉換成 ASCII 字元(character)的功能。
{x: chr(x) for x in [65,90,97,122]}
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
留意上圖顯示,如果我們輸入 chr(65)
會回傳 ‘a’。這符合我們文初的 ASCII 索引表裡,以 ASCII 65 代表小寫 ‘a’ 的。而英文字母的 ASCII 表索引是從 65 至 90 和 97 至 122 的。
參考上面的 alphabet_index()
功能,我們也可以寫出類似的的「索引至英文字母」功能。我們先一起看看以下例子:
def indexToAlphabet(ind: int, upperCase: bool = False):
if ind < 1 or ind > 26:
raise NotImplementedError('請輸入 1 至 26 之間的整數')
if upperCase:
return chr(ord('A') + ind - 1)
else:
return chr(ord('a') + ind - 1)
# 現在我們試一下不同情況的回傳
for x in [(1, False), (1, True), (17, True), (27, False)]:
try:
print('輸入:', x, '\n輸出:', indexToAlphabet(x[0],x[1]),'\n')
except Exception as e:
print('輸入:', x, '\n輸出:', e,'\n')
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
這個 indexToAlphabet
有 2 個輸入:索引(例如我們輸入 1 會見到 ‘a’ 或 ‘A’)和大寫(如果輸入 True 會見到 ‘A’)。
- 如果輸入的索引小於 1 或大於 26,那麼我們不能回傳一個英文字母,所以我們回傳一個錯誤(Error)
- 如果用戶選擇
upperCase = True
便回傳相應的大寫英文字母,否則回傳小寫
教學完整代碼
最後送給大家這篇教學的 Google Colab 完整代碼。如果您不懂得使用免安裝又好用的 Google Colab Notebook,記得閱讀這篇教學了:新手 1/3:5 分鐘免安裝學習 Python?Google Colab Notebook 幫緊您!
結語
希望大家如果在 Python 面試遇到類似問題時,可以想起 ord()
和 chr()
,成功擄獲面試官的芳心!