AtCoderのABC146 B問題で、Unicodeに慣れ親しむ機会がありました。
アルファベット文字列を「N文字分ずらす」とは「アルファベット順でN文字後ろのものに変換する」動作を表し、'Z'の次は'A'に戻るとします。上述のB問題でも同様の定義です。
組み込み関数ord()
とchr()
Python3には組み込み関数ord()
とchr()
が実装されており、文字とそのUnicodeコードポイントを互いに変換して返してくれます。
参考:[Python3.8公式ドキュメント#ord]
(https://docs.python.org/ja/3/library/functions.html#ord)
>>> ord('A')
65
>>> ord('D')
68
>>> chr(65)
'A'
>>> chr(70)
'F'
分かったように「Unicodeコードポイント」とか言ってますが、「いろんな文字記号を数字と1対1対応させて表してる世界なんやな」ぐらいの認識で突破です。
日本語が、とかいろんな表し方が、とかは奥が深い世界なので良さそうな本に丸投げします。
どうやら大文字のアルファベットに関しては'A'がコード65で、そこから10進数の連番になっていますね。
ちなみに大文字と小文字の間には
>>> ord('Z')
90
>>> chr(91)
'['
>>> chr(92)
'\\'
>>> chr(93)
']'
>>> chr(94)
'^'
>>> chr(95)
'_'
>>> chr(96)
'`'
>>> chr(97)
'a'
と、いくつか記号が挟まってました。へー。
実装の注意点
引数でお気づきかもしれませんがord()
もchr()
も一文字の変換を想定しています。
文字列Sを変換する際には空文字列''
に、for
文で一文字づつ変換しては結合してを繰り返します。
そして'Z'から'A'に戻る時も考慮するため、元の文字コードポイントにN加えた整数を26で割った余り
を、'A'のコードポイントに足し合わせることで変換後の文字コードポイントを算出します。
def rot_n(s, n):
answer = ''
for letter in s:
answer += chr(ord('A') + (ord(letter)-ord('A')+n) % 26)
return answer
確認してみます。
>>> rot_n('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 13)
'NOPQRSTUVWXYZABCDEFGHIJKLM'
AtCoder B問題での提出はコチラ↓
def rot_n():
n = int(input())
s = input()
answer = ''
for letter in s:
answer += chr(ord('A') + (ord(letter)-ord('A')+n) % 26)
print(answer)
if __name__ == '__main__':
rot_n()
ちなみに変換後の文字列Sを元に戻す(N文字前にずらす)関数は
def derot_n(s, n):
answer = ''
for letter in s:
answer += chr(ord('Z') - (ord('Z')-ord(letter)+n) % 26)
return answer
となります。
>>> derot_n('NOPQRSTUVWXYZABCDEFGHIJKLM', 13)
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
雑記:ROT N?
冒頭で書いたAtCoderの問題で知りました。
13文字後ろにずらす簡単な暗号であるROT13を一般化してたんですね。