JavaScriptでQuineする

Quineとは

クワイン(英: Quine)は、コンピュータプログラムの一種で、自身のソースコードと完全に同じ文字列を出力するプログラムである。

https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AF%E3%82%A4%E3%83%B3_(%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0)

ソースコード自体を文字列として出力します。字面にすると簡単そうですが、これが意外と奥が深いのです。

例えば、console.log('a')とした場合、出力はaとなります。
これではダメなので、console.log("console.log('a')")としてみましょう。
すると出力は、console.log('a')

一筋縄では上手くいきません。

// この方法じゃダメだ...
console.log('a') // a
console.log("console.log('a')") // console.log('a')
console.log("console.log(\"console.log('a')\")") // console.log("console.log('a')")
...

今回は、node <file名>.jsの形で実行した時の標準出力で確認します。

(おそらく)一番簡単に

(function (){console.log('('+arguments.callee+')()')})()

arguments.calleeは悪なのか

argumentsオブジェクトが持つcalleeプロパティは、そのargumentsオブジェクトを呼び出した関数自身を参照するプロパティです。

ECMAScript第5版(ES5)以降では、Strictモードでcalleeプロパティ自体は使用できません(エラーになる)

arguments.callee がなぜStrictモードでエラーになるのか。詳細は以下記事にて。

evalを使うパターン

eval(x="y=String.fromCharCode(34);console.log(('eval(x='+y+x+y+')'))")

ちなみに、String.fromCharCode(34)は、"を表します。

String.fromCharCode() - JavaScript | MDN
String.fromCharCode() 静的メソッドは、指定された UTF-16 コード単位の並びから生成された文字列を返します。

evalはリスクがあるから使わない?

evalは、引数に指定した文字列をJavaScriptのコードとして実行する関数です。

evalには次のようなリスクがあることが分かっています。

  1. 悪意の第3者が用意したJavaScriptプログラムを実行できてしまうセキュリティリスク。
  2. 通常のJavaScriptプログラムを実行するより速度が低下してしまうパフォーマンス劣化リスク。

このため、現在ではevalを使用することは一般的ではないです。

変数展開のパターン

JSには、変数展開がない!?

大丈夫。replaceがある!

(function(){console.log('(function(){console.log(_.replace(/(.*?)_(.*)(.)(.)/,"$1$3$1_$2$4$3$4$4$3$2"));})()\'\\'.replace(/(.*?)_(.*)(.)(.)/,"$1$3$1_$2$4$3$4$4$3$2"));})()

replaceで変数展開?

前述の通り、replaceで変数展開っぽいことをしています。
replaceの挙動はこんなイメージ

console.log('pen#apple'.replace(/(.*)#(.*)/,'$1, $2, $2$1!'))
// pen, apple, applepen!

王道(?)のパターン

ネットで調べてみると、この方法が最小で書けるかな

(function a(){console.log("("+a+")()")})()

functionに名前つけて、そのまま出力しています。

ずるいやつ

はい、何も書きません。
node <file名>.js を実行すると何も出力されないので、成功です。

wikipediaによれば、

いくつかのプログラミング言語(の処理系)は空のソースコードを受け取って、何も行わない、という動作をするので、それを利用する手もある。そのような空のプログラムがIOCCCで「規則のはなはだしい悪用」賞を受賞したこともある。

https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AF%E3%82%A4%E3%83%B3_(%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0)

とのこと。素晴らしい(?)

ちなみに同ページによると、このような空のプログラムでは、

通常、この問題を解いたものとはみなされない。

https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AF%E3%82%A4%E3%83%B3_(%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0)

そうですw

まとめ

業務では絶対書かないコード群でした。たまにはこういうのもいいですね。

次は、別の言語でやってみよう。

参考

JavaScriptでQuine書いてみたよ! - プログラムモグモグ
前から, Quineというものがあることは知っていたのですが, 難しそうでずーっと避けていました.なんとなく気になって書いて見た.Quineと言うのは, ソースコードと全く同じ内容を出力するようなプログラムです.書いてる時には, 「あっちを...
タイトルとURLをコピーしました