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;}
Depende do coreutils + dc
.
Experimente online!
Isso foi ... uma jornada.
Esta resposta tem três partes. As 4 primeiras linhas lidam com certos casos especiais para simplificar o código a seguir. As próximas 2 linhas e a última linha realizam essencialmente a mesma coisa, mas exatamente uma é executada com qualquer remoção de caractere. Eles são escritos com conjuntos de caracteres principalmente complementares, para que a remoção de qualquer caractere quebre apenas um, permitindo que o outro continue funcionando.
Olhando para a primeira parte, primeiro lidamos com
- remoção de nova linha com
ec\nho \\n
- remoção de espaço com
ca t<<<$'\x20'
(seguido de exi t
para evitar a execução de código posterior, o que resultaria em saída estranha)
$
remoção com d$c -e8BC6P
( 8BC6
= 9226
is 36*256 + 10
e 36 e 10 são os valores de bytes dos $
caracteres newline e respectivamente; usamos dígitos hexadecimais em decimal para evitar a necessidade de incluí-los no grande comentário da linha 6)
0
remoção com d0c -eKp
( K
obtém a precisão decimal, que é 0
por padrão)
Na próxima parte, os únicos caracteres usados (além do lixo no final da segunda linha) são $'\01234567v;
espaço e nova linha. Destas, quatro foram contabilizadas, portanto o restante ( '\1234567v
) não pode ocorrer na última linha. Expandindo as fugas octais ( $'\123'
representa o caractere ASCII com o valor 123 8 ), obtemos:
zsh -c 'for v in {#..\}};{ fgrep -q $v '$0'||<<<$v;}'
eval ':;:&&exit'
A primeira linha percorre todos os caracteres usados no programa e procura cada um em seu próprio código-fonte ( $0
é o nome do arquivo do script que está sendo executado), imprimindo qualquer caractere que não seja encontrado.
A segunda linha parece um pouco estranha e parece fazer a mesma coisa que exit
com um monte de nops. No entanto, a codificação exit
como octal resulta diretamente em $'\145\170\151\164'
, que não contém 2
ou 3
. Na verdade, precisamos tornar isso menos resistente a remoções. Isso ocorre porque, se algum '\014567v
deles for removido, quebrando a primeira linha, a segunda linha também será interrompida, permitindo a execução do restante do código. No entanto, precisamos também quebrar se 2
ou 3
forem removidos para que as linhas 3 e 4 possam ser executadas. Isso é conseguido pela calçadeira em :
e ;
, que tem 2 e 3 em sua representação octal, respectivamente.
O lixo eletrônico no final da linha 2 está simplesmente lá para garantir que todos os caracteres ASCII imprimíveis apareçam pelo menos uma vez, pois a maneira como a verificação é feita percorrendo cada um deles exige isso.
Se exit
não foi chamado na primeira seção (isto é, foi mutilado pela remoção de uma '\01234567v
), passamos para a segunda, na qual devemos realizar a mesma coisa sem usar nenhum desses caracteres. A última linha é semelhante à primeira linha decodificada, exceto que podemos contratar o intervalo do loop para salvar alguns bytes, porque já sabemos que todos os caracteres, exceto os '\01234567v
, foram cobertos. Ele também tem 0# $#
antes, o que comenta e impede que produza uma saída estranha se 0
ou $
foi removido.