Polyglot

2009年7月20日 (月)

記号でPolyglotプログラミング♪(RejectKaigi2009)

RubyKaigi2009の最終日に同じ場所で開催された別のイベント「RejectKaigi2009」にて 「はじめてのRuby1.9プログラミング」と題して、記号Polyglotプログラミングの話をしてきました。

3分という限られた時間でありましたが、貴重な発表の機会を与えてくださりありがとうございます。

取り急ぎプレゼンで披露した記号Polyglotのプログラムを公開しておきます。

■ hello.pl

(という名前ですが、Perlの他にRubyやJavaScriptでも実行できるプログラムです)

■ 各言語処理系での実行結果

(1) Perl の実行結果

D:\rejectkaigi2009> perl hello.pl
Hello, Perl!

(2) Ruby 1.8.7 での実行結果

D:\rejectkaigi2009> ruby1.8 hello.pl
Hello, Ruby1.8!

(3) Ruby 1.9.1 での実行結果

D:\rejectkaigi2009> ruby1.9 hello.pl
Hello, Ruby1.9!

(4) SpiderMonkey での実行結果

D:\rejectkaigi2009> js hello.pl
Hello, JavaScript!

(5) Firefox での実行結果

ブラウザのURL入力欄にjavascript:を入力してその後にワンライナーをコピペして改行(Enter)を押します。

Demo_firefox

(6) Chrome での実行結果

Firefoxの場合と同様にします。javascript:を入力し忘れないでください。(でないと入力した記号のワンライナーをGoogle検索しにいってしまってBad Requestと怒られてしまいます…)

Demo_chrome

■ Ruby部分のコード解説

PerlとJavaScriptのコードは後日解説するとして、Ruby部分のコードで使われているテクニックを少し解説しようと思います。(最初に言い訳ですが、まだRuby1.9を使い始めて3日目なので、間違ったことを言っていたらすみません…)

Rubyインタプリタの解釈する部分は以下になります。

Polyglot_ruby

それ以外のところはPerlやJavaScriptで実行される領域になっています。

- Ruby 1.8 と 1.9 の非互換部分

Ruby1.8以前では ?a は'a'のASCIIコードの数値97が返されていましたが、Ruby1.9からは長さ1の文字列"a"を返すように仕様変更されました。これはRuby1.9からの多言語対応のためで、文字列をバイト列ではなく文字単位で扱うようになったためです。

ruby1.9> p ?a
"a"

ruby1.8> p ?a
97

したがって、?? は Ruby1.9では文字列"?"のことですが、Ruby1.8以前では'?'のアスキーコードである63の数値を返すことになります。

ruby1.9> p ??
"?"

ruby1.8> p ??
63

次に数値と文字列における%演算子の違いですが、文字列の"?"%"?"はsprintf("?","?")と同じ動きをして結果は"?"となりますが、数値の63%63は63÷63=商1…余り0の余りを返すため0となります。

ruby1.9> p ??%??
"?"

ruby1.8> p ??%??
0

これを利用してRuby1.9の処理系かどうかを記号9バイトだけで判定することができます。RUBY_VERSION を使うよりも圧倒的に短いです。地球に優しくてエコですね。:-)

ruby1.9> p ??%??==??
true

ruby1.8> p ??%??==??
false

- 記号のみで任意の文字列を作成する方法

Rubyで任意の文字列を生成するには""<<数値(ASCIIコード)という文字列の破壊的演算を行なう構文を利用するのが簡単です。

ruby1.9> p ''<<123
"{"

ruby1.8> p ''<<123
"{"

任意の数値を作成するには、Ruby1.8以前では?{-?|などを利用してできたのですが、Ruby1.9からは先の仕様変更があるため使えません。どうするかというと、正規表現を利用します。

ruby1.9> p //=~''
0

ruby1.8> p //=~''
0

正規表現にマッチした場所を文字列の先頭から数えて結果を返します。

ruby1.9> p /_/=~'>_'
1

ruby1.8> p /_/=~'>_'
1

これを利用すると、こちらで用意した文字列から目的の先頭バイト数でマッチする正規表現を書いてあげれば、任意の数値を作成することができます。これは記号だけを使って実現できます。

ruby1.9> p /_/=~'>>>>>>>>>_'
9

ruby1.8> p /_/=~'>>>>>>>>>_'
9

- (''<<数値)で任意のASCIIコードの文字を標準出力 $> に書き込む

以上のテクニックを組み合わせると、$> << "文字列" と書くことを利用して任意の文字列を標準出力に書き込むことができます。

ruby1.9> $><<(''<<88)+(''<<89)+(''<<90)
XYZ

ruby1.8> $><<(''<<88)+(''<<89)+(''<<90)
XYZ

もちろん、88や89の数字の部分は上記で解説したテクニックを応用して、数値返す正規表現(記号のみ)に置き換えています。真面目にゴルフすればもっと短くなることはわかっているのですが、まずは「わかりやすさ優先」ということであえて冗長なコードになっています。

実際のコードではPerlとJavaScriptとRubyのコードを混在させるために、別のテクニックも使っているのですが、詳しい解説はまた後日行ないたいと思います。

それでは、Happy Hacking!

2008年11月11日 (火)

/. Happy Binary Day ! /.

スラッシュドットJPによると、本日11月11日はバイナリデーだそうです。

バイナリデーを祝うべく、/.Jにもちょっとしたイースターエッグを仕込んでおきました。 /.Jのとある場所に、日本のバイナリ/ハッカー界の著名人の方々から頂戴した祝賀 コメントを掲載しています。/.J読者皆様、ぜひお探しの上一緒にバイナリデーを お祝いいただけるとうれしいです。

とのことで、小生も 祝賀コメントとネタのバイナリファイルを寄稿いたしました。

※ 11/12 8:22 追記 時効ということでイースターエッグのURLを直リンしました

■ 0x457.html (0x457 = 1111)

HTML EBCDIC JavaScript Linux ELF x86 Golf Polyglot です。

0x457.html

(1) Safari3 で表示した結果

Safari3

(2) IE7 で表示した結果 (IE6では表示できません)

1111ie7.png

例のファイルですが、 Safari3 と IE7 で動作確認しています。Firefox, Opera では動作しません。

(3) Linux ELF x86 として実行した場合

1111x86.png

Linux ELF x86 は CentOS release 4.7 (Linux 2.6.9-55.0.12.EL i686 i386 GNU/Linux) で 動作確認しています。最近の x86_64 の環境だと動作しないかもしれません。

(4) VT100端末で表示した場合

1111vt100.png

どうぞご利用ください。

種明かしはのちほど。