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 tper evitare l'esecuzione di codice successivo, che comporterebbe un output estraneo)
$rimozione con d$c -e8BC6P( 8BC6= 9226is 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)
0rimozione con d0c -eKp( Kottiene la precisione decimale, che è 0di 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 exitdi un mucchio di nops. Tuttavia, la codifica exitcome ottale risulta direttamente $'\145\170\151\164', che non contiene 2o 3. Dobbiamo effettivamente renderlo meno resistente alle traslochi. Questo perché se uno di questi '\014567vviene 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 2o 3vengono 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 exitnon è 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 '\01234567vsono stati coperti. Ha anche 0# $#davanti, che lo commenta e gli impedisce di produrre output estraneo se 0o $fosse rimosso.