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 de coreutils + dc
.
Pruébalo en línea!
Eso fue ... un viaje.
Esta respuesta tiene tres partes. Las primeras 4 líneas manejan ciertos casos especiales para simplificar el código que sigue. Las siguientes 2 líneas y la última línea logran esencialmente lo mismo, pero exactamente una se ejecuta con cualquier eliminación de caracteres. Se escriben con conjuntos de caracteres en su mayoría complementarios, por lo que eliminar cualquier carácter rompe solo uno como máximo, permitiendo que el otro continúe funcionando.
Mirando la primera parte, primero manejamos
- eliminación de nueva línea con
ec\nho \\n
- eliminación de espacio con
ca t<<<$'\x20'
(seguido de exi t
para evitar ejecutar código posterior, lo que daría como resultado una salida extraña)
$
eliminación con d$c -e8BC6P
( 8BC6
= 9226
es 36*256 + 10
, y 36 y 10 son los valores de byte de los $
caracteres de línea nueva y respectivamente; utilizamos dígitos hexadecimales en decimal para evitar tener que incluirlos en el comentario grande en la línea 6)
0
eliminación con d0c -eKp
( K
obtiene la precisión decimal, que es la 0
predeterminada)
En la siguiente parte, los únicos caracteres utilizados (aparte de la basura al final de la segunda línea) son $'\01234567v;
espacio y nueva línea. De estos, cuatro se han contabilizado, por lo que el resto ( '\1234567v
) no puede aparecer en la última línea. Al expandir los escapes octales ( $'\123'
representa el carácter ASCII con el valor 123 8 ), obtenemos:
zsh -c 'for v in {#..\}};{ fgrep -q $v '$0'||<<<$v;}'
eval ':;:&&exit'
La primera línea recorre todos los caracteres utilizados en el programa y busca cada uno en su propio código fuente ( $0
es el nombre de archivo del script que se está ejecutando), imprimiendo cualquier carácter que no se encuentre.
La segunda línea parece un poco extraña, y parece hacer lo mismo que exit
con un montón de nops. Sin embargo, la codificación exit
como octal da como resultado directamente $'\145\170\151\164'
, lo que no contiene 2
o 3
. De hecho, necesitamos hacer esto menos resistente a las mudanzas. Esto se debe a que si '\014567v
se elimina alguno de ellos, se rompe la primera línea, la segunda línea también se rompe, permitiendo que se ejecute el resto del código. Sin embargo, necesitamos que también se rompa si se eliminan 2
o 3
se eliminan para que las líneas 3 y 4 puedan ejecutarse. Esto se logra calzando zapatos en :
y ;
, que tienen un 2 y un 3 en su representación octal, respectivamente.
La basura al final de la línea 2 simplemente está ahí para garantizar que todos los caracteres ASCII imprimibles aparezcan al menos una vez, ya que la forma en que se realiza la comprobación recorriendo cada uno requiere esto.
Si exit
no se llamó en la primera sección (es decir, fue destruida por la eliminación de uno de '\01234567v
), pasamos a la segunda, en la que debemos lograr lo mismo sin usar ninguno de estos caracteres. La última línea es similar a la primera línea decodificada, excepto que podemos contraer el rango del bucle para guardar algunos bytes, porque ya sabemos que todos los caracteres, excepto el, '\01234567v
han sido cubiertos. También tiene 0# $#
delante, lo que lo comenta y evita que produzca resultados extraños si se eliminaron 0
o $
no.