Tociyuki::Diary RSSフィード

tociyuki によるPerl・Rubyのコード説明を中心に、日常雑記も混在 : B  F  twitter  GitHub  CPAN  本館
 | 

2006年12月04日

[][]Re: 'SAKURA' → 'HZPFIZ' な暗号文を復号する

⇒ sumim さんの「’SAKURA’ -> ’HZPFIZ’ な暗号文を復号する

こういうのは Perl and/or 正規表現が得意そう…

ということで、PerlRuby でワンライナをやってみました。以下、ワンライナのしきたりに従い、コマンドライン・オプション -p を付けて記述量を減らしています。

まずは、文字置換を使った素直な解。

$ echo HZPFIZ | perl -pe 'tr/A-Z/ZYXWVUTSRQPONMLKJIHGFEDCBA/'
$ echo HZPFIZ | ruby -pe '$_.tr!("A-Z", "ZYXWVUTSRQPONMLKJIHGFEDCBA")'

続いて、プログラミングしているふりをする解。

$ echo HZPFIZ | perl -pe '$" = ""; eval qq{tr/A-Z/@{[reverse "A".."Z"]}/};'
$ echo HZPFIZ | perl -pe 'eval qq{tr/A-Z/@{[join "", reverse "A".."Z"]}/};'
$ echo HZPFIZ | perl -pe 'eval qq{tr/@{["A".."Z"]}/@{[reverse "A".."Z"]}/};'
$ echo HZPFIZ | perl -pe '@T = ("A".."Z"); eval qq{tr/@T/@{[reverse @T]}/};'

$ echo HZPFIZ | ruby -pe '$_.tr!("A-Z", ("A".."Z").to_a.reverse.join)'
$ echo HZPFIZ | ruby -pe '$_.tr!(("A".."Z").to_a.join, ("A".."Z").to_a.reverse.join)'

Perl の eval で tr 演算子の変数展開をする方法は、ラクダ本認定公式イディオムです。なお、置換される方を A-Z と書くときは、配列要素間に余計な空白を展開させないために、空文字列を $" 変数にセットするか、空文字列をセパレータにして join する必要があります。

一方、Ruby ではそのような気遣いは不要ですが、文字列しか tr! の引数に渡せず、join メソッド(to_s でも可)が必須です。tr! に Range オブジェクトや Array オブジェクトが渡せるといいのにっ。

文字列置換を使って上の tr と同じことをおこなう解。Ruby 版は省略します。

$ echo HZPFIZ | perl -pe 'BEGIN{@T = ("A".."Z"); @T{@T} = reverse @T} s/[@{[join "", @T]}]/$T{$&}/geo;'

続いて、数式計算による解。

$ echo HZPFIZ | perl -pe 's/[A-Z]/chr(155 - ord($&))/ge;'
$ echo HZPFIZ | ruby -pe '$_.gsub!(/[A-Z]/) { (155 - $&[0]).chr }'

数字 155 は、chr("Z") + chr("A") のことです。

これを、join split で書き直そうとすると、A-Z 以外の文字を置換しないように条件判定しなければなりません。

$ echo HZPFIZ | perl -pe '$_ = join "", map { $_ ge "A" && $_ le "Z" ? chr(155 - ord($_)) : $_ } split //'
$ echo HZPFIZ | ruby -pe '$_ = $_.split(//).map{ |c| c >= "A" && c <= "Z" ? (155 - c[0]).chr : c }.join'

以上の中で、Perl の数式計算による文字列置換の解が最もエレガントに記述できているなと思いました。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

 |