quainsの書き方

はじめに


多くのプログラマーは、 クイン (ソースコードを出力するプログラム)の作成は圧倒的な作業だと考えています。 そして確かに-これらのチェーンのすべてとさまざまな順序のクイン、それらを見ると、一見無意味なキャラクターのセットで迷子になる可能性があります...



しかし、実際には、どんな言語でもクインを書くことは見た目ほど難しくありません。 次に、さまざまなプログラミング言語でこれを行う方法を説明します。 さらに、ソースコードやevalなどの関数を出力する操作など、インタープリター言語の「ハック」を使用せず、インタープリター言語およびコンパイル済み言語でクインを作成します。



理論


馬を書きましょう。 これを行うには、出力用の言語命令を受け取り、プログラムコードをパラメーターとして渡します。 ただし、コードでは再び同じコードを使用するなど、無限再帰が発生します。 しかし、文字列定数を渡さないために何ができるでしょうか? 解決策は、文字列(コードの一部のコピー)を変数に入れることです。 便宜上、このような文字列をs-stringと呼び、この文字列を持つ変数をs-variableと呼びます 。 s変数の再帰を防ぐために、この変数自体の値を持つフラグメントを単純に除外します。 つまり、次のようになります。



C:
char s[]="char s[]=;";
      
      





ご注意 このフラグメントでは、結果となるはずの領域と同様に、簡単にするために、コードのフォーマットの規則に従いません。 それでも、記事を読んだ後は、自分で簡単に実施できます。



さらに、出力時に、コード内の定義でs-stringの値を置き換えます(上記の例では、最後の3文字の前)。 ここで、さらにいくつかの問題が発生します。 最初の問題は、s-lineで置換する場合、コード内で異なる動作をする文字を使用できないことです。 たとえば、引用符を挿入することはできません-s-stringの一部になる代わりに定義を完了し、表示されたコードは元のコードと一致せず、まったく正しくないためです。



ここでエスケープを適用するのはかなり困難です-エスケープ文字もエスケープする必要があります。たとえば、異なるバージョンの引用符を使用する方がはるかに簡単です-たとえば、多くの解釈言語では、単一または二重引用符を使用して文字列を指定できますが、違いはある引用符が他の引用符に限定されていれば、問題なく定数内で1つの引用符を使用することができます。 つまり、コード'"'



は、二重引用符付きの単一文字列と、単一引用符付きのコード"'"



を作成します。このオプションを使用する場合は、変数の先頭に引用符を付けて、出力で使用すると便利です。



ただし、このオプションは一般的ではありません。たとえば、Cでは、引用符のオプションは1つだけです。 次に、別の方法を使用できます-文字コードで引用符を指定し、そのようなコードで文字を出力で印刷します。



次の問題は、s-lineの出力に別の行(またはコードを持つ文字)を挿入することです。 ここでの解決策は明らかです-特別な関数を使用してs-stringの部分文字列を取得し、それを出力し、挿入する必要があるものを出力し、s-stringの別の部分文字列を出力します。 Cでは、出力用の部分文字列を取得するには多くのコードが必要になるようです。 ここで、printf関数のパワーが役立ちます。 そのため、たとえば、2番目の文字(1からカウント)から4番目までの文字列sの一部を印刷する、さまざまな言語のコードオプションを次に示します。



Python:
 print(s[1:4])
      
      





ルビー:
 print s[1..3]
      
      





Perl:
 print substr(s,1,2)
      
      





C:
 printf("%.2s",s+1);
      
      





通常、サブストリングメソッドは、残りを最後まで取得することもできます。 たとえば、2番目の文字から行の最後まで文字列sを出力します(つまり、最初の文字を除く行全体)。



Python:
 print(s[1:])
      
      





ルビー:
 print s[1..-1]
      
      





Perl:
 print substr(s,1)
      
      





C:
 printf("%s",s+1);
      
      





これが不可能な場合は、パラメーターをサブストリングの長さで「XX」タイプのスタブに置き換え、最後にコードのさまざまな部分の長さを変更せずに、コードとs-lineで文字を最後までカウントし、「XX」に置き換える必要があります。 たとえば、長さが1桁の場合、最初のxの代わりにスペースを使用することをお勧めします。削除すると、s-string部分の長さが変化し、再カウントする必要があるためです。



通訳言語


それでは、クインを書き始め、上記のすべての判断を集めましょう。 Pythonでは、このクインを書きました( 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:])
      
      





ここで、q変数は単一引用符が格納される変数として使用され、s変数はs文字列自体を除くすべてのコードで定義されます。 その後、次の挿入を含むs変数の出力が続きます。

1)。 qの値としての単一引用符。

2)。 s-string定義の始まりとしての単一引用符。

3)。 s-string自体(はい、s-stringはs-stringの内側に挿入されます);

4)。 s-string定義の終わりとしての単一引用符。



ご注意 このメソッドを使用してクインを記述するときは、コード内のすべての変更をs-lineのコードのコピーにコピーすることを忘れないでください。



最小限の変更で、 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:]
      
      





他の言語のクインもまったく同じです。ここでは、いくつかの構文機能のみを変更します。



ルビー:
 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);
      
      





コンパイルされた言語。


Cでクインを書くのはもう少し難しいことがわかっています。 ここでは、文字コードを積極的に使用しました:二重引用符-34、改行-13(stdio.hを含めるためにコンパイラディレクティブを分離する必要がありました)、および前述のprintfを使用して部分文字列を取得する興味深い方法です。



そして、これがクインそのものです。

 #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;}
      
      





おわりに


以上です。 私はほとんどの言語、コンピューターで見つけたインタープリターとコンパイラーでクウェインを書きました。 ここで言及していなければ、あなた自身がお気に入りのプログラミング言語で同様のプログラムを書くと思います。 演習として、Java、C#、Haskell、Pascalなどの言語でクインを書くこともできます。 困難を恐れないでください-試してみてください、すべてがうまくいきます!



All Articles