こんにちは!
3ヶ月で、Elixir言語で開発できるようになるため、奮闘中のこーへーです!
期間が空きましたが、8つ目の問題をどうにかこうにかクリアできたので、アップしていきたいと思います。
08. 暗号文Permalink
与えられた文字列の各文字を,以下の仕様で変換する関数cipherを実装せよ
- 英小文字ならば(219 - 文字コード)の文字に置換
- その他の文字はそのまま出力
この関数を用い,英語のメッセージを暗号化・復号化せよ
Cipherモジュールとconversion関数の作成
defmodule Cipher do
def conversion(input_text) do
input_text
|> String.graphemes()
|> Enum.map(fn x -> conversion_char(x) end)
|> Enum.join()
end
上記関数で、String.grahemes()
を使っていますが、ここはcodepoints
でも実現したいことは変わりません。ただ、grahemesは、Unicodeを解釈してくれる機能があります。
例えば、\u0065\u0301
を変換すると次のようになります。
iex(30)> String.graphemes("\u0065\u0301")
["é"]
基本的には、各要素に分割した文字列リストを返してくれます。
conversion_char関数の作成
def conversion_char(x) do
<<c :: utf8>> = x
if c >= ?a and c <= ?z do
<<219 - c :: utf8>>
else
x
end
end
これは、なかなかギョッとしますよね。
まず、<<c :: utf8>> = x
の部分ですが、xに入ってきた文字を1文字づつ取り出して、cにバインドしています。
もし、utf8でなければエラーが発生します。
その次のif文は英子文字であるかをチェックしています。
正直ここは書き方がわからなかったので、少しチョンボしましたがこういう書き方があるんだと勉強になりました。
というわけで、全体を繋げると以下のようになります。
defmodule Cipher do
def conversion(input_text) do
input_text
|> String.graphemes()
|> Enum.map(fn x -> conversion_char(x) end)
|> Enum.join()
end
@spec conversion_char(binary()) :: binary()
def conversion_char(x) do
<<c :: utf8>> = x
if c >= ?a and c <= ?z do
<<219 - c :: utf8>>
else
x
end
end
end
実行すると以下のようになります。
iex(32)> Cipher.conversion("すずき")
"すずき"
iex(33)> Cipher.conversion("abc")
"zyx"
iex(34)> Cipher.conversion("0123")
"0123"
iex(35)> Cipher.conversion("ABC")
"ABC"
iex(36)> Cipher.conversion("/////")
"/////"
iex(37)> Cipher.conversion(".......")
"......."
2つ目に実行した"abc"
という文字列は暗号化されて、それ以外はそのまま(復号化)されていることがわかるかと思います。
まとめ
今回の問題では、conversion関数の中で、conversion_char関数の呼び出しを行っています。
今までは、関数ひとつひとつを作ってそれぞれ実行していましたが、初の試みだったのでより柔軟な発想が必要だと感じました。