Introduction
Many programmers consider writing
quines (programs that output their source code) to be a daunting task. And really - all these chain quines and quine of a different order, when looking at which you can get lost in the seemingly meaningless set of characters ...
However, in fact, writing quine in any language is not as difficult as it seems. Now I will tell you how to do this in various programming languages. Moreover, we will not use "hacks" of interpreted languages like the operation of outputting source code and functions like eval and writing quains in interpreted and compiled languages.
Theory
Let's try to write a quine. To do this, take the language instruction for output and pass it as a parameter to the program code. However, in the code we use the same code again and so on - endless recursion occurs. But what can be done in order not to pass a string constant? The solution is to put a string (a copy of a part of the code) into a variable. For convenience, we call such a string an
s-string , and a variable with this string is an
s-variable . So that there is no recursion in the s-variable, we simply exclude from it a fragment with the value of this variable itself. That is, it will look something like this:
C:char s[]="char s[]=;";
Note. Both in this fragment and in quineas, which will be obtained in the end, for simplicity, we will not follow the rules of code formatting. Nevertheless, you can easily add them yourself after reading the article.')
Further, in the output, we will substitute the value of the s-line in its definition in the code (in the example above, before the last three characters). Here there are some more problems. The first problem is that when substituting in the s-line it is impossible to use characters that will not behave in the code as it should. For example, we cannot simply insert a quotation mark - after all, instead of becoming part of the s-line, it will complete its definition and the output code will not match the source code, being incorrect at all.
It is quite difficult to apply screening here — the screening symbol must also be escaped, etc. It is much simpler, for example, to use another version of quotes — for example, many interpreted languages allow using both single and double quotes to specify a string, and the difference is That it is possible to use without problems one quotation mark in a constant if it is limited to others. That is, the code
'"'
creates a single-character string with a double quote, and the code
"'"
with a single character. If you use this option, it is convenient to set a variable with a quote at the beginning, and then use it in the output.
But this option is not universal: in C, for example, there is only one option for quotes. Then you can use another way - to set the quote character code, typing the character with the code in the output.
The next problem is inserting another string (or a character with some code) into the s-string output. The solution here is obvious - take the substring of the s-string with a special function, output it, then output what you need to insert, then output another substring of the s-string. It may seem that in C, taking a substring for output will require a lot of code. This is where the power of the printf function comes in. So, for example, here are the code variants for various languages, printing part of the string s from the second character (counting from one) to the fourth inclusive:
Python: print(s[1:4])
Ruby: print s[1..3]
Perl: print substr(s,1,2)
C: printf("%.2s",s+1)
Typically, methods for taking a substring can also take its remainder to the end. For example, we print the string s from the second character to the end of the line (that is, the entire line except the first character):
Python: print(s[1:])
Ruby: print s[1..-1]
Perl: print substr(s,1)
C: printf("%s",s+1);
If this is not possible, you will have to replace the parameter with the length of the substring of type “XX”, and then at the end count the characters to the end and substitute them instead of “XX” in the code and in the s-line, without changing the length of different parts of the code. For example, if the length is one digit, it is advisable to substitute a space instead of the first X, because if you delete it, the lengths of the s-line parts will change and you will have to recalculate them.
Interpreted languages
So, let's start writing quines, having collected all the judgments above. In
Python, I wrote such a quine (it works on
3.x ):
q="'";s='q="";s=;print(s[:3]+q+s[3:7]+q+s+q+s[7:])';print(s[:3]+q+s[3:7]+q+s+q+s[7:])
Here, the q variable is used as a variable where a single quote is stored, followed by the definition of an s-variable with all the code except for the s-string itself. After that comes the output of the s-variable with the following inserts:
one). A single quote as the value of q;
2). Single quotation mark as the beginning of the s-string definition;
3). The s-string itself (yes, the s-string is inserted inside the s-string);
four). Single quotation mark as the end of the s-string definition.
Note. When writing quineas using this method, do not forget to copy all changes in the code into a copy of the code in the s-line.With minimal changes, you can get Quine only for
Python 2.x :
q="'";s='q="";s=;print s[:3]+q+s[3:7]+q+s+q+s[7:]';print s[:3]+q+s[3:7]+q+s+q+s[7:]
Quains in other languages are completely analogous, where we change only some syntactic features:
Ruby: q="'";s='q="";s=;print s[0..2]+q+s[3..6]+q+s+q+s[7..-1]';print s[0..2]+q+s[3..6]+q+s+q+s[7..-1]
Perl: $q="'";$s='$q="";$s=;print substr($s,0,4).$q.substr($s,4,5).$q.$s.$q.substr($s,9)';print substr($s,0,4).$q.substr($s,4,5).$q.$s.$q.substr($s,9)
PHP: <?$q="'";$s='<?$q="";$s=;print substr($s,0,6).$q.substr($s,6,5).$q.$s.$q.substr($s,11);';print substr($s,0,6).$q.substr($s,6,5).$q.$s.$q.substr($s,11);
Compiled languages.
Writing a quine in
C turned out to be a little more difficult. Here I actively used character codes: double quotes - 34, and line feeds - 13 (it was needed to separate the compiler directive to include stdio.h), as well as an interesting way to take a substring using printf, already described above.
And here is Quine himself:
#include <stdio.h> int main(){const char *s="#include <stdio.h>int main(){const char *s=;printf(%.18s%c%.25s%c%s%c%.8s%c%.33s%c%s,s,10,s+18,34,s,34,s+43,34,s+51,34,s+84);return 0;}";printf("%.18s%c%.25s%c%s%c%.8s%c%.33s%c%s",s,10,s+18,34,s,34,s+43,34,s+51,34,s+84);return 0;}
Conclusion
That's all. I wrote quines in most languages, the interpreters and compilers of which I found on my computer. I think that now you yourself will write a similar program in your favorite programming language, if I have not mentioned it here. As an exercise, you can also write a quine in languages such as Java, C #, Haskell, or Pascal. Do not be afraid of difficulties - just try, and everything will work out!