除了作弊¹之外,编译语言和解释语言之间没有区别。
quines 的通用方法非常简单。首先,无论程序是什么样的,在某些时候它必须打印一些东西:
打印 ...
但是,它应该打印什么?本身。所以它需要打印“打印”命令:
打印“打印...”
接下来应该打印什么?好吧,与此同时程序也在增长,所以它也需要打印以“print”开头的字符串:
打印“打印\”打印...\“”
现在程序再次增长,所以还有更多要打印的内容:
打印"打印\"打印\\\"...\\\"\""
等等。每添加一个代码,就会有更多代码要打印。这种方法无济于事,但它揭示了一个有趣的模式:字符串“print \”“一遍又一遍地重复。将重复部分放入变量中会很好:
a = "打印\""
打印一个
但是,程序刚刚改了,所以我们需要调整一个:
a = "a = ...\n打印一个"
打印一个
当我们现在尝试填写“...”时,我们遇到了和以前一样的问题。最终,我们想写这样的东西:
a = "a = " + (a 的引用内容) + "\nprint a"
打印一个
但这是不可能的,因为即使我们有这样的quoted()
引用功能,仍然存在我们a
根据自身定义的问题:
a = "a = " + 引用(a) + "\nprint a"
打印一个
所以我们唯一能做的就是将占位符放入a
:
a = "a = @\n打印一个"
打印一个
这就是全部技巧!现在其他任何事情都清楚了。只需将占位符替换为以下引用的内容a
:
a = "a = @\n打印一个"
打印 a.replace("@", 引用(a))
由于我们更改了代码,我们需要调整字符串:
a = "a = @\nprint a.replace(\"@\", 引用(a))"
打印 a.replace("@", 引用(a))
就是这样!所有语言的所有 quines 都以这种方式工作(作弊的除外)。
那么,您应该确保只替换第一次出现的占位符。如果你使用第二个占位符,你可以避免需要引用字符串。
但这些都是小问题,很容易解决。事实上,实现quoted()
和replace()
是各种 quines 真正不同的唯一细节。
¹ 通过让程序读取其源文件