除了作弊¹之外,编译语言和解释语言没有区别。
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 真正不同的唯一细节。
¹通过让程序读取其源文件