C, 59 byte
i;f(char*s){while(*s&3?*s&9||(i+=i+*s%5):putchar(i),*s++);}
Numeri magici, numeri magici ovunque!
(Inoltre, C più corto di Python, JS, PHP e Ruby? Inaudito!)
Questa è una funzione che accetta una stringa come input e output su STDOUT.
Procedura dettagliata
La struttura di base è:
i; // initialize an integer i to 0
f(char*s){
while(...); // run the stuff inside until it becomes 0
}
Qui, "stuff inside" è un gruppo di codice seguito da ,*s++, in cui l'operatore virgola restituisce solo il valore del suo secondo argomento. Quindi, questo verrà eseguito attraverso la stringa e impostato *ssu ogni carattere, incluso il byte NUL finale (poiché postfix ++restituisce il valore precedente), prima di uscire.
Diamo un'occhiata al resto:
*s&3?*s&9||(i+=i+*s%5):putchar(i)
Staccando il ternario e il corto circuito ||, questo può essere espanso
if (*s & 3) {
if (!(*s & 9)) {
i += i + *s % 5;
}
} else {
putchar(i);
}
Da dove vengono questi numeri magici? Ecco le rappresentazioni binarie di tutti i personaggi coinvolti:
F 70 01000110
B 66 01000010
i 105 01101001
z 122 01111010
u 117 01110101
32 00100000
\0 0 00000000
Innanzitutto, dobbiamo separare lo spazio e NUL dal resto dei personaggi. Il modo in cui funziona questo algoritmo mantiene un accumulatore del numero "corrente" e lo stampa ogni volta che raggiunge uno spazio o la fine della stringa (cioè '\0'). Notando che ' 'e '\0'sono gli unici caratteri a non avere nessuno dei due bit meno significativi impostati, possiamo bit a bit E il carattere con 0b11ottenere zero se il carattere è spazio o NUL e diverso da zero.
Scavando più a fondo, nel primo ramo "if", ora abbiamo un personaggio di cui è uno FBizu. Ho scelto solo di aggiornare l'accumulatore su Fs e Bs, quindi avevo bisogno di un modo per filtrare izus. Convenientemente, Fed Bentrambi hanno solo il secondo, il terzo o il settimo bit meno significativo impostato, e tutti gli altri numeri hanno almeno un altro bit impostato. In effetti, tutti hanno il primo o il quarto bit meno significativo. Quindi, possiamo bit a bit AND con 0b00001001, che è 9, che produrrà 0 per Fe Be diverso da zero.
Una volta stabilito che abbiamo un Fo B, possiamo mapparli 0e 1rispettivamente prendendo il loro modulo 5, perché Fè 70ed Bè 66. Quindi lo snippet
i += i + *s % 5;
è solo un modo di dire golfy
i = (i * 2) + (*s % 5);
che può anche essere espresso come
i = (i << 1) | (*s % 5);
che inserisce il nuovo bit nella posizione meno significativa e sposta tutto il resto su 1.
"Ma aspetta!" potresti protestare. "Dopo la stampa i, quando viene ripristinato su 0?" Bene, putcharlancia il suo argomento a un unsigned char, che in questo caso ha una dimensione di 8 bit. Ciò significa che tutto ciò che è passato dall'ottavo bit meno significativo (ovvero la spazzatura delle precedenti iterazioni) viene eliminato e non dobbiamo preoccuparci.
Grazie a @ETHproductions per aver suggerito di sostituire 57con 9, salvando un byte!