zsh, 603 594 566 561 548 440 415 399 378 370 bytes
ec
ho \\n;ca t<<<$'\x20';exi t
d$c -e8BC6P
d0c -eKp
$'\172\163\150' $'\055\143' $'\146\157\162 v \151\156 \173\043\056\056\134\175\175\073\173 \146\147\162\145\160 \055\161 $\166 '$0$'\174\174\074\074\074$\166\073\175'
$'\145v\141\154' $':\073\072\046\046\145\170\151\164';#%&()*+,/9=>?@ADEFGHIJLMNOQRSTUVWXYZ[]^_`jklmsuwy
0# $#;for b in {$..z};{ fgrep -q $b $0||<<<$b;}
Depends on coreutils + dc
.
Try it online!
That was... a journey.
Ця відповідь має три частини. Перші 4 рядки обробляють певні особливі випадки для спрощення коду, що випливає. Наступні два рядки і останній рядки виконують по суті одне і те ж, але саме один запускається з будь-яким видаленням символів. Вони записуються в основному взаємодоповнюючими наборами символів, так що видалення будь-яких символів порушує лише один максимум, що дозволяє іншому продовжувати функціонувати.
Дивлячись на першу частину, ми спочатку справляємося
- видалення нового рядка з
ec\nho \\n
- видалення місця з
ca t<<<$'\x20'
(з подальшим exi t
уникненням запуску більш пізнього коду, що призведе до стороннього виводу)
$
видалення з d$c -e8BC6P
( 8BC6
= 9226
є 36*256 + 10
, а 36 і 10 - значення байтів $
символів і рядків у новому рядку відповідно; ми використовуємо шістнадцяткові цифри у десяткових знаках, щоб уникнути необхідності включення їх у великий коментар у рядку 6)
0
видалення з d0c -eKp
( K
отримує десяткову точність, яка 0
за замовчуванням)
У наступній частині використовуються єдині символи (окрім сміття в кінці другого рядка) $'\01234567v;
, пробіл та новий рядок. З них четверо були обліковані, тому решта ( '\1234567v
) не може бути в останньому рядку. Розгортаючи восьмеричні втечі ( $'\123'
представляє символ ASCII зі значенням 123 8 ), отримуємо:
zsh -c 'for v in {#..\}};{ fgrep -q $v '$0'||<<<$v;}'
eval ':;:&&exit'
Перший рядок пробирає всі символи, які використовуються в програмі, і шукає кожного з них у власному вихідному коді ( $0
це ім'я файлу запущеного сценарію), друкуючи будь-який символ, який не знайдено.
Другий рядок виглядає дещо дивно, і, здається, робить те саме, що і exit
з купою сосків. Однак кодування exit
як вісімкового прямо призводить до того $'\145\170\151\164'
, що не містить 2
або 3
. Нам фактично потрібно зробити це менш стійким до видалення. Це відбувається тому, що якщо будь-який з '\014567v
видалених, порушуючи перший рядок, другий рядок також розривається, дозволяючи виконувати залишок коду. Однак нам це потрібно, щоб воно також було розірвано, якщо 2
або 3
видалено, щоб лінії 3 і 4 могли працювати. Це досягається за допомогою вбирання в :
і;
, which have a 2 and 3 in their octal representation respectively.
Небажана в кінці рядка 2 просто є для того, щоб кожен друкуваний символ ASCII, який можна роздрукувати, з’явився хоча б один раз, оскільки цього вимагає спосіб перевірки шляхом прокручування кожного з них.
Якщо exit
в першому розділі не було викликано (тобто воно було порушено видаленням одного з '\01234567v
), ми переходимо до другого, в якому ми повинні виконати те саме, не використовуючи жодного з цих символів. Останній рядок схожий на декодований перший рядок, за винятком того, що ми можемо скоротити діапазон циклу, щоб зберегти кілька байт, тому що ми вже знаємо, що всі символи, за винятком '\01234567v
, були охоплені. Він також має 0# $#
перед цим, який коментує це та заважає йому створювати сторонні результати, якщо 0
або $
були видалені.