ASCIIコードのPythonでの扱い方
今回はPyhtonでASCIIコードを扱う方法を、ABC146Bを使って説明していきます。UTFには触れていませんので、機会があれば別記事を書きたいと思います。
問題はこちら
問題を解く前に
Pyhtonで
- 文字→ASCIIコード
- ASCIIコード→文字
への変換方法を紹介します。
#文字→ASCIIコード
AsciiCode = ord('A')
print(AsciiCode)
#出力は65
#ASCIIコード→文字
character = chr(65)
print(character)
#出力はA
組み込み関数である**ord()とchr()**だけ知っていれば事前知識は十分です。あと、$A$のASCIIコードは$65$、$Z$のASCIIコードは$90$であること、またASCIIコード$91$は$a$であることを知っておくとよいと思います。(厳密にはASCIIというよりユニコードなのですが、ユニコードはASCIIと矛盾しないよう拡張して作られているので、ここではASCIIで貫きます)
問題文
英大文字のみからなる文字列$S$があります。また、整数$N$が与えられます。$S$の各文字を、アルファベット順で$N$個後の文字に置き換えた文字列を出力してください。ただしアルファベット順で$Z$の$1$個後の文字は$A$とみなします。
入力
入力は以下の形式で標準入力から与えられる。
N
S
解答1
N = int(input())
S = input()
newS = ''
for char in S:
if ord(char)+N > 90:
newS += chr(ord(char)-26 + N)
else:
newS += chr(ord(char)+N)
print(newS)
短いのですが簡単に説明します。$N$や$S$を入力した後、$newS$という空の文字列を作っておきます。そして、$S$の要素を一つ一つ見ていき、
newS += chr(ord(char)+N)
の部分で、$char$という文字のASCIIコードを求め、何個後の文字にしたいかを表す$N$を足した後、文字に戻すということをしています。
ポイントは、
if ord(char)+N > 90:
newS += chr(ord(char)-26 + N)
の部分で、$Z$の1個後の文字は$A$になってほしいわけです。
なので、$ord(char)+N$が$Z$のASCIIコードである$90$を超えてしまう場合には、1周期分の$26$を引いて対応しています。
ACではあるけれども...
このコード、問題があります。ACは出ましたが汎用性がまるでありません。もし$N$に$1000$といった数が与えられたらどうなるでしょう。
$S$として$ABC$、$N$として$1000$を入力してみました。出力は以下のようになります。
ЏAБ
意図しない文字が出てしまいました。
解答2
大きな$N$にも周期性をもって対応するには、次のようにするとよいです。
N = int(input())
S = input()
newS = ''
for char in S:
newS += chr((ord(char) - ord('A') + N) % 26 + ord('A'))
print(newS)
入力は前と同じです。大事なのは
for char in S:
newS += chr((ord(char) - ord('A') + N) % 26 + ord('A'))
のforループです。
この部分は、Aを基準にどのくらい先の文字を出力するかという考え方をしています。例えば
$ord('B') - ord('A')$は$1$になります。$B$は$A$の$1$個後の文字だからです。コードの$ord(char) - ord('A') + N$の部分は、$A$の何個後の文字にしたいかを表しています。
しかしこの部分が$A$の$1000$個後であったら困るので、周期的になるようアルファベットの数である$26$で割った余りにしているわけです。
例えば**$27$個後の文字にしたい=$1$個後の文字にしたい**といった具合です。
これにより、$N$に大きな数を入力しても周期的にアルファベットを変更してくれる汎用的なコードになります。
余談
$ord()$や$chr()$について本当はもっと説明が必要かもしれません。僕の認識では、
- ユニコード→文字
- 文字→ユニコード
の変換をしているに過ぎない認識ですが...
何かあれは説明しないの?これは説明しないの?みたいなのがあればご指摘等お願い致します。