rot13は、シーザー暗号の発展版みたいなもので、abcdeという文字列が合った場合、13文字ずらしてnopqrという文字列を出力する素敵な暗号のこと。実装方法自体はココにあるんです。しかもHaskellとScala。ちょうどいい。
langref.org - scala and haskell - Strings | Manipulation | Simple substitution cipher
イカ引用。13文字バージョンだけではなく、47文字ずらすバージョンも実装してくれてる。
val uppers = 'A' to 'Z' val lowers = 'a' to 'z' val alpha13 = (uppers ++ lowers).mkString val beta13 = ((uppers drop 13) ++ (uppers take 13) ++ (lowers drop 13) ++ (lowers take 13)).mkString val alpha47 = """!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~""" val beta47 = """PQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO""" // generic translation function def rot (alpha: String, beta: String)(c: Char) = if (alpha contains c) beta(alpha indexOf c) else c // specific translation functions curried with the respective alphabets val rot13 = rot(alpha13, beta13) _ val rot47 = rot(alpha47, beta47) _ assert(("Hello World #123" map rot13).toString == "Uryyb Jbeyq #123") assert(("Hello World #123" map rot47).toString == "w6==@ (@C=5 R`ab")
import Char ebg13 c | isAlpha c && toLower c <= 'm' = chr ((ord c) + 13) | isAlpha c && toLower c > 'm' = chr ((ord c) - 13) | otherwise = c rot13 str = map ebg13 str ebg47 c | c > ' ' && c <= 'N' = chr ((ord c) + 47) | c > 'N' && c <= '~' = chr ((ord c) - 47) | otherwise = c rot47 str = map ebg47 str
見たら分かると思うのですが、実装方法がScalaとHaskellではぜんぜん違う。というわけで、とりあえず、うえのHaskellの例を直訳してみる。直訳といっても、HaskellのisALphaに相当する関数がScalaにはないようなので、そこは正規表現でごまかしてみる。
原理としては、Char値を数値に変換、演算して、さらにtoCharで変換する、というHaskellプログラムの流れを踏襲してる。
def alpha13(c: Char): Char = c match { case c if c.toString.matches("[A-Za-z]") && c.toLower <= 'm' => (c.toInt + 13).toChar case c if c.toString.matches("[A-Za-z]") && c.toLower >= 'm' => (c.toInt - 13).toChar case _ => c } def rot13(str: String): String = { str.map(c => alpha13(c)) } println(rot13("abcde")) // nopqr println(rot13("I am shigemk2")) // V nz fuvtrzx2 println(rot13("z")) // m