プログラミングHaskell (第五章の練習問題・シーザーの暗号)

in

5.7 (8) シーザー暗号のプログラムを大文字も扱えるように変更せよ

だんだん、プログラムらしくなってきました。問題のシーザー暗号のプログラムがどこまでのことを指すのか今ひとつわかりませんでしたが、crackの箇所は大文字の出現頻度がわからないのでとりあえず、暗号化するところまで。まず、let2intを改造して大文字もint変換できるように修正します。

let2int' ::Char -> Int
let2int' c | isUpper c = ord c - ord 'A'
           | otherwise = ord c

悩みましたが、大文字を基準にしてあとはそのままコード値を返します。当然、コード値から文字に変換するint2letも修正します。

int2let' ::Int -> Char
int2let' n | n >= 0 && n <= 25 = chr (ord 'A' + n)
           | otherwise = chr n

['A'..'Z']が[0..25]に変換されているはずなのでそれらは'A'を基準に変換します。

後はshift関数を修正すればいいのですが、'A'..'Z'をシフトするのはテキストの例題どおりで良いと思うのですが、小文字が与えられた場合の変換方法はなかなか巧い手を考え出すことができず苦労しました。で、最終的に思いついたのが、"いったん'A'..'Z'と同じ状態にしちゃう"というちょっと汚いテ。

shift' :: Int -> Char -> Char
shift' n c | isLower c = int2let'(((let2int' c) - ord 'a' + n) `mod` 26 + ord 'a')
           | isUpper c = int2let'((let2int' c + n) `mod` 26)
           | otherwise = c

つまり、'a'..'z'に対するlet2intからord 'a'を引くと0..25になるはずなのでその状態になれば例題と同じやり方でshiftできるわけです。で、戻すときこっそりord 'a'を足しといてやればいい。かなり荒技ですが一応動作するかと...

encode' :: Int -> String -> String
encode' n xs = [shift' n x | x <- xs ]

encodeからの呼び出しをshift'に変えて、

*Main> encode' 3 "HASKELL IS FUN"
"KDVNHOO LV IXQ"
*Main> encode' (-3) "KDVNHOO LV IXQ"
"HASKELL IS FUN"

模範解答は以下のとおりでした。

shift' :: Int -> Char -> Char
shift' n c | isLower c = int2low ((low2int c + n ) `mod` 26)
           | isUpper c = int2upp ((upp2int c + n ) `mod` 26)
           | otherwise = c

freqs' ::String -> [Float]
freqs' xs = [percent (count x xs') n | x <- ['a'..'z']]
           where
            xs' = map toLower xs
            n = letters xs

low2int :: Char -> Int
low2int c =  ord c - ord 'a'

int2low :: Int -> Char
int2low n = chr (ord 'a' + n)

upp2int :: Char -> Int
upp2int c = ord c - ord 'A'

int2upp :: Int -> Char
int2upp n = chr (ord 'A' +  n)

letters :: String -> Int
letters xs = length [x | x <- xs,isAlpha x]

パッと見、あ〜、freqsぅう。内心、ここまでやるのだろうなと思いつつも言い訳してやらなかったので大減点です。で、肝心の暗号化の部分ですがもちろん模範解答のほうがスッキリしています。元のコードに囚われてしまいそれを無理矢理修正しているあたり我ながらセンスのなさを感じます。たぶん、僕の解答では自分自身数週間を経ずして何をしようとしていたのか思い出せないでしょう。職業プログラマにはあるまじきことです。念のため、僕のencode'でもcrackできるか試してみました。

*Main> encode' 3 "Haskell is FUN!!!"
"Kdvnhoo lv IXQ!!!"
*Main> crack "Kdvnhoo lv IXQ!!!"
"Haskell is FUN!!!"

いや、ほんと楽しくなってきました。が、そろそろ鬼門の章が見えてきて...

添付サイズ
ceaser.hs2.31 KB

この記事のトラックバックURL:

http://hippos-lab.com/blog/trackback/352

Comments