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++оператор з комами повертає лише значення другого аргументу. Отже, це буде проходити через рядок і встановлюватись *sдля кожного символу, включаючи кінцевий байт NUL (оскільки постфікс ++повертає попереднє значення) перед виходом.
Давайте подивимось на решту:
*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'є єдиними символами, які не мають жодного з двох найменш значущих бітів, ми можемо побітовим І символом з, 0b11щоб отримати нуль, якщо символ є пробілом або NUL, а не нульовим значенням є інше.
Копаючи глибше, у першій «якщо» гілці, тепер у нас є персонаж, який є одним із FBizu. Я вибрав лише оновлення акумулятора на Fs і Bs, тому мені знадобився якийсь спосіб відфільтрувати izus. Зручно, Fі Bобидва мають лише другий, третій чи сьомий найменш значущі біти, а всі інші числа мають принаймні один інший біт. Насправді всі вони мають або перший, або четвертий найменш значущий біт. Отже, ми можемо побіжно AND з 0b00001001, що дорівнює 9, що дасть 0 для Fі, Bа не нульове значення в іншому випадку.
Як тільки ми визначимо, що у нас є Fабо B, ми можемо відобразити їх відповідно 0і 1, взявши їх модуль 5, тому що Fє 70і Bє 66. Потім фрагмент
i += i + *s % 5;
- це просто грізний спосіб сказати
i = (i * 2) + (*s % 5);
що також можна виразити як
i = (i << 1) | (*s % 5);
який вставляє новий біт принаймні значущому положенні та зміщує все інше на 1.
"Але чекай!" ви можете протестувати. "Коли ви надрукуєте i, коли це колись повернеться до 0?" Що ж, putcharприводить свій аргумент до unsigned charвеличини, яка так само буває, що має 8 біт. Це означає, що все, що минуло восьмий найменш значущий біт (тобто мотлох від попередніх ітерацій), викидається, і нам не потрібно про це турбуватися.
Завдяки @ETHproductions для пропонуючи замінити 57з 9, зберігаючи байт!