zsh, 603 594 566 561 548 440 415 399 378 370 byte
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;}
Dipende da coreutils + dc
.
Provalo online!
Quello era ... un viaggio.
Questa risposta ha tre parti. Le prime 4 righe gestiscono alcuni casi speciali per semplificare il codice che segue. Le successive 2 righe e l'ultima riga realizzano entrambe essenzialmente la stessa cosa, ma esattamente una viene eseguita con qualsiasi rimozione di carattere. Sono scritti con set di caratteri per lo più complementari, in modo che la rimozione di qualsiasi personaggio ne rompa solo uno al massimo, consentendo all'altro di continuare a funzionare.
Guardando la prima parte, per prima cosa ci occupiamo
- rimozione di newline con
ec\nho \\n
- rimozione dello spazio con
ca t<<<$'\x20'
(seguita da exi t
per evitare l'esecuzione di codice successivo, che comporterebbe un output estraneo)
$
rimozione con d$c -e8BC6P
( 8BC6
= 9226
is 36*256 + 10
, e 36 e 10 sono i valori byte rispettivamente dei $
caratteri newline; usiamo le cifre esadecimali in decimali per evitare di doverle includere nel commento grande nella riga 6)
0
rimozione con d0c -eKp
( K
ottiene la precisione decimale, che è 0
di default)
Nella parte successiva, gli unici caratteri utilizzati (a parte la spazzatura alla fine della seconda riga) sono $'\01234567v;
, spazio e newline. Di questi, quattro sono stati presi in considerazione, quindi il resto ( '\1234567v
) non può verificarsi nell'ultima riga. Espandendo le fughe ottali ( $'\123'
rappresenta il carattere ASCII con valore 123 8 ), otteniamo:
zsh -c 'for v in {#..\}};{ fgrep -q $v '$0'||<<<$v;}'
eval ':;:&&exit'
La prima riga scorre tutti i caratteri utilizzati nel programma e cerca ciascuno nel proprio codice sorgente ( $0
è il nome file dello script in esecuzione), stampando qualsiasi carattere non trovato.
La seconda riga sembra un po 'strana e sembra fare la stessa cosa exit
di un mucchio di nops. Tuttavia, la codifica exit
come ottale risulta direttamente $'\145\170\151\164'
, che non contiene 2
o 3
. Dobbiamo effettivamente renderlo meno resistente alle traslochi. Questo perché se uno di questi '\014567v
viene rimosso, interrompendo la prima riga, anche la seconda riga si interrompe, consentendo l'esecuzione del resto del codice. Tuttavia, abbiamo bisogno che si interrompa anche se 2
o 3
vengono rimossi in modo che le linee 3 e 4 possano essere eseguite. Ciò si ottiene con il pattino in :
e ;
, che hanno rispettivamente un 2 e un 3 nella loro rappresentazione ottale.
La spazzatura alla fine della riga 2 è semplicemente lì per garantire che ogni carattere ASCII stampabile appaia almeno una volta, poiché il modo in cui il controllo viene eseguito ciclicamente attraverso ognuno di essi lo richiede.
Se exit
non è stato chiamato nella prima sezione (cioè è stato rovinato dalla rimozione di uno dei '\01234567v
), passiamo alla seconda, in cui dobbiamo realizzare la stessa cosa senza usare nessuno di questi personaggi. L'ultima riga è simile alla prima riga decodificata, tranne per il fatto che possiamo contrarre l'intervallo del loop per salvare alcuni byte, perché sappiamo già che tutti i caratteri tranne quelli '\01234567v
sono stati coperti. Ha anche 0# $#
davanti, che lo commenta e gli impedisce di produrre output estraneo se 0
o $
fosse rimosso.