C、59バイト
i;f(char*s){while(*s&3?*s&9||(i+=i+*s%5):putchar(i),*s++);}
マジックナンバー、どこでもマジックナンバー!
(また、CはPython、JS、PHP、Rubyよりも短いですか?
これは、入力として文字列を受け取り、STDOUTに出力する関数です。
ウォークスルー
基本構造は次のとおりです。
i; // initialize an integer i to 0
f(char*s){
while(...); // run the stuff inside until it becomes 0
}
ここでは、「内部の内容」はに続くコードの束で,*s++あり、カンマ演算子は2番目の引数の値のみを返します。したがって、終了する前に、これは文字列*s全体を実行し、末尾のNULバイトを含むすべての文字に設定されます(postfix ++は前の値を返すため)。
残りを見てみましょう:
*s&3?*s&9||(i+=i+*s%5):putchar(i)
三元および短絡をはがすと||、これは
if (*s & 3) {
if (!(*s & 9)) {
i += i + *s % 5;
}
} else {
putchar(i);
}
これらのマジックナンバーはどこから来たのですか?関連するすべての文字のバイナリ表現は次のとおりです。
F 70 01000110
B 66 01000010
i 105 01101001
z 122 01111010
u 117 01110101
32 00100000
\0 0 00000000
最初に、スペースとNULを残りの文字から分離する必要があります。このアルゴリズムの動作方法は、「現在の」数のアキュムレータを保持し、スペースまたは文字列の終わり(つまり'\0')に達するたびにそれを出力します。ことを注目して' 'と'\0'設定された2つの最下位ビットのいずれかを持っていない唯一の文字であるが、我々は、ビット単位のANDできると文字0b11の文字がそれ以外のスペースやNULとゼロでない場合には、ゼロを取得します。
深く掘り下げると、最初の「if」ブランチで、次のいずれかのキャラクターができましたFBizu。FsとBsのアキュムレータのみを更新することを選択したため、sを除外する方法が必要でしたizu。便利なことにF、B両方とも2番目、3番目、または7番目の最下位ビットのみが設定されており、他のすべての数値には少なくとも1つの他のビットが設定されています。実際、それらはすべて最初または4番目の最下位ビットを持っています。したがって、ビットごとにANDを使用してANDを実行できます0b00001001。これは、9でありF、Bandが0で、それ以外の場合はゼロではありません。
For があることを確認したら、is およびis であるため、それらのモジュラス5を取得することによりB、0およびにマッピングできます。次にスニペット1F70B66
i += i + *s % 5;
ただのゴルフのような言い方です
i = (i * 2) + (*s % 5);
次のように表現することもできます
i = (i << 1) | (*s % 5);
最下位の位置に新しいビットを挿入し、他のすべてを1にシフトします。
"ちょっと待って!" あなたは抗議するかもしれません。「印刷後i、いつ0にリセットされますか?」さて、putchar引数をにキャストするとunsigned char、たまたま8ビットのサイズになります。つまり、8番目の最下位ビット(つまり、以前の反復からのジャンク)を超えるものはすべて破棄され、心配する必要はありません。
おかげ@ETHproductions交換することを示唆しているため57に9、バイトを節約!