zsh, 603 594 566 561 548 440 415 399 378 370 bajtów
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;}
Zależy od coreutils + dc
.
Wypróbuj online!
To była ... podróż.
Ta odpowiedź składa się z trzech części. Pierwsze 4 wiersze obsługują określone przypadki specjalne w celu uproszczenia następującego kodu. Kolejne 2 linie i ostatnia linia osiągają zasadniczo to samo, ale dokładnie jedna jest uruchamiana z dowolnym usunięciem znaku. Są one napisane przy użyciu głównie komplementarnych zestawów znaków, więc usunięcie dowolnego znaku psuje tylko jeden, co pozwala drugiemu dalej funkcjonować.
Patrząc na pierwszą część, najpierw zajmiemy się
- usuwanie nowej linii za pomocą
ec\nho \\n
- usuwanie miejsca za pomocą
ca t<<<$'\x20'
(następnie następuje, exi t
aby uniknąć uruchamiania późniejszego kodu, co spowodowałoby powstanie obcych danych wyjściowych)
$
usunięcie za pomocą d$c -e8BC6P
( 8BC6
= 9226
is 36*256 + 10
, a 36 i 10 są odpowiednio bajtowymi $
znakami nowego i nowego wiersza; używamy cyfr szesnastkowych dziesiętnych, aby uniknąć konieczności dołączania ich do dużego komentarza w wierszu 6)
0
usuwanie z d0c -eKp
( K
pobiera dokładność dziesiętną, która jest 0
domyślnie)
W następnej części jedynymi używanymi znakami (oprócz śmieci na końcu drugiego wiersza) są $'\01234567v;
spacja i nowa linia. Cztery z nich zostały uwzględnione, więc reszta ( '\1234567v
) nie może wystąpić w ostatnim wierszu. Po rozwinięciu liczb ósemkowych ( $'\123'
reprezentuje znak ASCII o wartości 123 8 ) otrzymujemy:
zsh -c 'for v in {#..\}};{ fgrep -q $v '$0'||<<<$v;}'
eval ':;:&&exit'
Pierwszy wiersz przechodzi przez wszystkie znaki używane w programie i wyszukuje każdy w swoim własnym kodzie źródłowym ( $0
jest nazwą pliku uruchamianego skryptu), wypisując dowolny znak, który nie został znaleziony.
Druga linia wygląda trochę dziwnie i wydaje się, że robi to samo, co exit
kilka band. Jednak kodowanie exit
ósemkowe powoduje bezpośrednio $'\145\170\151\164'
, który nie zawiera 2
lub 3
. W rzeczywistości musimy uczynić to mniej odpornym na przeprowadzki. Wynika to z faktu, że jeśli którykolwiek z nich '\014567v
zostanie usunięty, zerwanie pierwszej linii, druga linia również się zepsuje, umożliwiając wykonanie pozostałej części kodu. Jednak musimy go również zepsuć, jeśli 2
lub 3
zostaną usunięte, aby linie 3 i 4 mogły działać. Odbywa się to poprzez wykuwanie butów w :
i ;
, które mają odpowiednio ósemkową reprezentację 2 i 3.
Śmieci na końcu wiersza 2 są po prostu po to, aby zapewnić, że każdy znak ASCII do wydruku pojawi się co najmniej raz, ponieważ wymaga tego sposób sprawdzania przez zapętlanie każdego z nich.
Jeśli exit
nie został wywołany w pierwszej sekcji (tzn. Został zniekształcony przez usunięcie jednego z '\01234567v
), przechodzimy do drugiej, w której musimy osiągnąć to samo bez użycia żadnej z tych postaci. Ostatnia linia jest podobna do dekodowanej pierwszej linii, z tym wyjątkiem, że możemy zawęzić zakres pętli, aby zaoszczędzić kilka bajtów, ponieważ wiemy już, że wszystkie znaki oprócz '\01234567v
. Ma również 0# $#
przed sobą, który komentuje to i zapobiega wytwarzaniu obcych danych wyjściowych, jeśli 0
lub $
zostały usunięte.