Rubyで簡易なシーザー暗号プログラムを作りました。
初投稿で、至らぬ点も多いですが、よろしくお願いします。
シーザー暗号とは?
平文の各文字を辞書順に3文字のみシフトし、暗号文をつくる暗号のこと。
単一換字式暗号の一種で、カエサル暗号とも呼ばれている。
要はアルファベット順に文字をシフトさせて、暗号化するってことですね。
例: enter → bkqbo
実現するには?
コードを実現するにあたって、考えたことは以下になります。
- 文字列って、数字で表現できるのでは?
- 文字列 → 数値 → シフト後の数値 → 文字列と変換すれば可能?
- 文字列が長くても対応できるように!
上記の3点を意識して、コードを書いてみました。
実際に書いたコード
puts "キーワードを入力してください(アルファベット小文字のみ)"
keyword = gets.chomp
puts "暗号化前: #{keyword}"
# 暗号化した文字列を格納するための配列を定義
code = []
# keyword.charsで入力された文字列を1文字ずつ分解して配列へ
keyword.chars.each do |char|
num = (char.ord - 3) # .ord で文字コードへ変換(数値化)し、3つ分、シフトする
code << num.chr # 文字コードを文字列へ戻し、配列codeに入れていく
end
# 配列codeに入った文字列を全て連結させて出力
puts "暗号化後: #{code.join("")}"
ターミナルでの出力
キーワードを入力してください(アルファベット小文字のみ)
desk
暗号化前: desk
暗号化後: abph
やった!できた! 他のも試してみよう・・・
キーワードを入力してください(アルファベット小文字のみ)
apple
暗号化前: apple
暗号化後: ^mmib
aが記号に変換されてしまった・・・
調べてみると、
aの文字コード: 97 → シフト後: 94 となり、文字コード: 94は「^」みたいです...
となると、「a ~ z」の文字コードでの範囲は「97 ~ 122」。この範囲外では、アルファベットの小文字ではなくなってしまう。
abcやxyzにも対応できるようにしなければ...
そこでコードを以下のように改良しました。
改良版
puts "パスワードを入力してください(aからzまでの小文字)"
keyword = gets.chomp
puts "暗号化前: #{keyword}"
code = []
keyword.chars.each do |char|
num = char.ord - 97
num2 = (num - 3) % 26
num3 = num2 + 97
code << num3.chr
end
puts "暗号化後: #{code.join("")}"
each文の中の処理を少し変更してみました!
each内部の処理ですが...
d を例として説明すると、
dの文字コードは「100」のため、numに入る値は「3」になります。
次にnumに対して、「3」(シフトさせる分の数値)を引き、 %26 してあげると num2は「0」です。
その後、num2に「97」を再び足すことでnum3が「97」となります。
最後に、このnum3に 「.chr」することで文字列に戻り、「a」となります。
num2の計算ですが、%26してあげることで、計算結果は「0 ~ 25」のどれかになります。
たとえ、num2が負の値であってもです。
これは割り算の余りの基本式に当てはめて考えてみると分かるので、気になる方はやってみてください。
(割られる数)=(割る数)×(商)+(余り)
最後に書き換えたコードをターミナルで実行してみましょう!
パスワードを入力してください(aからzまでの小文字)
apple
暗号化前: apple
暗号化後: xmmib
アルファベットの小文字限定ですが、無事暗号化することができました。
まだ大文字や数字には対応していないので、時間があればやってみようかと思います。
分かりづらかったかもしれませんが、ここまで読んでいただきありがとうございました。