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)
は、"
を表します。
evalはリスクがあるから使わない?
eval
は、引数に指定した文字列をJavaScriptのコードとして実行する関数です。
eval
には次のようなリスクがあることが分かっています。
- 悪意の第3者が用意したJavaScriptプログラムを実行できてしまうセキュリティリスク。
- 通常の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
まとめ
業務では絶対書かないコード群でした。たまにはこういうのもいいですね。
次は、別の言語でやってみよう。
参考
JSのQuineは簡単すぎるからなぁ「!function f(){console.log(“!”+f+”()”)}()」
— がお (@gaogao_9) November 28, 2014