Symbolic Polyglot Quine
題字の通り。作ろうかなぁと思いつつ作ってなかったので作りました。
http://shinh.skr.jp/obf/sym_poly_quine.txt
一応ある程度サイズは気にして作りましたが、細かいゴルフとかは全然してません。 Perl がなんか知らんけど SEGV しやがるので eval の中でやりたい処理を全部外でやってるので長くなってしまった…まぁブラウザの認識とかしてないとはいえ TAKESAKOさんのhello の半分以下ですんでるんでいいんじゃないかな。
ブラウザで試す場合はこのへん。 IE 以外だったら大抵のブラウザで大丈夫なんじゃないでしょうか。 IE は文字列の中の一文字を [] で取ってこれないのでアウト。
ある程度短くしようとしてたので、エスケープとかがわけわからんくならないように基本的にバックスラッシュ封印してコードを書く必要があって、バックスラッシュ封印すると必然的にシングルクォートも実行コード中では使えなくなるので、まぁそのへんが大変でした。ついでに今回は空白と改行も封印してみた。空白はともかく改行はだいぶ自由度が減りますね。
あとは基本的には下記にあるような技術しか使ってません。
あとはまぁ、 Ruby の記号での文字列出力とか各言語の切り替えとかは、まぁやりゃなんとでもなるですね。
短くするために、 JS の部分はあまり jjencode 的な数値を変換するようなことはせずに、ほぼ primitive から取ってこれる文字だけで処理しました。クォートとかそのへんは %27 とかを unescape しました。バックスラッシュが使えないので "\047" は使えません。 'p' は jjencode で使ってる primitive の中には無いのだけど、 (/_/.constructor+"")[14] にあったのでめでたしめでたし。あとは this の 'h' だけ取ってこれなかったので、そこは unescape に頼りました。ていうかブラウザ内で実行されてるかどうかの判定って
_ = this.alert; _ = _ ? _ : print;
とかしてるわけですが、もっといい方法ありそうだよなぁと思います。あと JS はメインの処理を eval 内に押し込めて重複コードを減らして短くする手法を使ってます。
Perl はなんか正規表現内でevalした中でevalした先で正規表現でevalすると SEGV するのが困りました。この SEGV が避けれるならメインの処理を eval 内に押し込められて、ちょっと短くなるんじゃないでしょうか。
Ruby は最初は 1.9 限定にして任意Rubyコードを記号化的なことをやっていたのですが、普通に eval の外で出力した方が $$.method.(:eval)[] とかするよりはるかに短くなったのでした。