¿Cómo puedo identificar un personaje extraño?

10

Estoy tratando de identificar un personaje extraño que he encontrado en un archivo con el que estoy trabajando:

$ cat file
�
$ od file
0000000 005353
0000002
$ od -c file
0000000 353  \n
0000002
$ od -x file
0000000 0aeb
0000002

El archivo está usando la codificación ISO-8859 y no se puede convertir a UTF-8:

$ iconv -f ISO-8859 -t UTF-8 file
iconv: conversion from `ISO-8859' is not supported
Try `iconv --help' or `iconv --usage' for more information.
$ iconv  -t UTF-8 file
iconv: illegal input sequence at position 0
$ file file
file: ISO-8859 text

Mi pregunta principal es ¿cómo puedo interpretar la salida de odaquí? Estoy tratando de usar esta página que me permite traducir entre diferentes representaciones de caracteres, pero me dice que 005353un "punto de código hexadecimal" es lo que no parece correcto y 0aebque un "punto de código hexadecimal" es lo que, nuevamente, parece incorrecto .

Así que, ¿cómo puedo usar cualquiera de las tres opciones ( 355, 005353o 0aeb) para averiguar qué personaje que se supone que representan?

Y sí, probé con las herramientas Unicode pero tampoco parece ser un carácter UTF válido:

$ uniprops $(cat file)
U+FFFD ‹�› \N{REPLACEMENT CHARACTER}
    \pS \p{So}
    All Any Assigned Common Zyyy So S Gr_Base Grapheme_Base Graph X_POSIX_Graph
       GrBase Other_Symbol Print X_POSIX_Print Symbol Specials Unicode

Si entiendo la descripción del personaje Unicode U + FFFD, no es un personaje real, sino un marcador de posición para un personaje corrupto. Lo cual tiene sentido ya que el archivo no está realmente codificado en UTF-8.

terdon
fuente
55
EB podría ser δ en la página de códigos 437 , o Ù en la página de códigos 850 , o ë en 8859-1 ; ¿Tendría sentido alguno de esos? (se iconvqueja porque no especificó el conjunto de caracteres de origen, por lo que utiliza su valor predeterminado que probablemente sea UTF-8.)
Stephen Kitt
@StephenKitt sí, ¡ ëes lo que veo cuando los datos se usan en otro programa! ¿Pero cómo puedo saber esto? ¿No está en algún lugar de los datos que proporciono? ¿Cómo lo encontraste? Oh, lo había intentado iconvcon -f ISO-8859pero se quejó de conversion from la norma ISO-8859' no se supported`.
terdon
1
Argh! Ya veo, necesitaba usar solo ebe ignorar el 0xindicador hexadecimal o lo que sea. Mi ignorancia de este tipo de cosas es profunda. ¿Podría publicar una respuesta explicando que @StephenKitt?
terdon
55
Su error crucial aquí es que ISO-8859 no es el nombre de una codificación. Es una familia de codificaciones; aparentemente, el que estás buscando es ISO-8859-1.
tripleee
1
Entonces tu iconvhabría tenido éxito; y / o podría haberlo buscado, por ejemplo, en Wikipedia. Para esta codificación muy específica, fileformat.info/info/unicode/char/00eb/index.htm también funciona (Unicode es equivalente a ISO-8859-1 en el rango 128-255, aunque, por supuesto, ninguna codificación UTF es compatible con él )
tripleee

Respuestas:

22

Su archivo contiene dos bytes, EB y 0A en hexadecimal. Es probable que el archivo esté usando un juego de caracteres con un byte por carácter, como ISO-8859-1 ; en ese conjunto de caracteres, EB es ë:

$ printf "\353\n" | iconv -f ISO-8859-1
ë

Otros candidatos serían δ en la página de códigos 437 , Ù en la página de códigos 850 ...

od -xEl resultado es confuso en este caso debido a la resistencia; una mejor opción es la -t x1que usa bytes individuales:

$ printf "\353\n" | od -t x1
0000000 eb 0a
0000002

od -xmapas a los od -t x2que se leen dos bytes a la vez, y en sistemas little endian emite los bytes en orden inverso.

Cuando se encuentra con un archivo como este, que no es válido UTF-8 (o no tiene sentido cuando se interpreta como un archivo UTF-8), no hay una forma infalible de determinar automáticamente su codificación (y conjunto de caracteres). El contexto puede ayudar: si se trata de un archivo producido en una PC occidental en las últimas dos décadas, existe una buena posibilidad de que esté codificado en ISO-8859-1, -15 (la variante del euro) o Windows-1252; si es más antiguo que eso, CP-437 y CP-850 son candidatos probables. Los archivos de sistemas de Europa del Este, o sistemas rusos, o sistemas asiáticos, usarían diferentes conjuntos de caracteres de los que no sé mucho. Luego está EBCDIC ... iconv -lenumerará todos los conjuntos de caracteres que iconvconoce, y puede proceder por ensayo y error desde allí.

(En un momento sabía de memoria la mayoría de CP-437 y ATASCII, esos eran los días).

Stephen Kitt
fuente
1
De acuerdo, en la página de Wikipedia a la que se vincula, puedo ver que ëse describe como 00EBy 234. ¿Qué son esos extra 00? ¿Y por qué no es 355como esperaba de la odsalida? Estoy tratando de obtener una respuesta más general sobre cómo puedo usar la odsalida para identificar el personaje. ¿Podría explicar algo sobre la interpretación de códigos hexadecimales y / o qué información se necesita para poder identificar un carácter desconocido (codificación y cualquier otra cosa)?
terdon
EB es 353 en octal (no 355). Trataré de generalizar ...
Stephen Kitt
Vaya, lo siento, me refería 353. Entonces el 353 es una representación octal, no decimal. Argh
terdon
1
Sí, la "o" en odsignifica octal ;-).
Stephen Kitt
1
En cualquier caso, el emulador de terminal mostraría el (U + FFFD) como un sustituto de ese byte 0xeb que no forma un carácter válido en UTF-8. No está claro por qué uniprops $(cat file)(las citas que faltan por cierto) reportarían eso (no sé sobre ese unipropscomando). unicode "$(cat file)"en Debian produce Sequence '\xeb' is not valid in charset 'UTF-8'como esperaba.
Stéphane Chazelas
5

Tenga en cuenta que odes la abreviatura de volcado octal , por 005353lo que los dos bytes como palabra octal, od -xestán 0aeben hexadecimal como palabra, y el contenido real de su archivo son los dos bytes eby 0aen hexadecimal, en este orden.

Entonces ambos 005353y 0aebno pueden ser interpretados simplemente como "punto de código hexadecimal".

0aes un avance de línea (LF) y ebdepende de su codificación. filesolo está adivinando la codificación, podría ser cualquier cosa. Sin más información de dónde vino el archivo, etc. será difícil averiguarlo.

dirkt
fuente
Me doy cuenta de esto porque no entiendo cómo funcionan los puntos de código (o hexadecimal, realmente), pero ¿cómo puedo saberlo? Usualmente uso od -cporque eso produce resultados que puedo entender. ¿Cómo podría haber usado el 355que produce para identificar al personaje? ¿Y por qué se imprime en 0aeblugar de eb0asi 0aes la nueva línea?
terdon
@terdon endianness ... Ver mi respuesta actualizada.
Stephen Kitt
2

Es imposible adivinar con un 100% de precisión el conjunto de caracteres de los archivos de texto.

Las herramientas como chardet , firefox , file -i cuando no se ha definido información explícita de juegos de caracteres (por ejemplo, si un HTML contiene un juego de caracteres meta = ... en la cabeza, las cosas son más fáciles) intentarán usar heurísticas que no son tan malas si El texto es lo suficientemente grande.

A continuación, demuestro la detección de conjunto de caracteres con chardet( pip install chardet/ apt-get install python-chardetsi es necesario).

$ echo "in Noël" | iconv -f utf8 -t latin1  | chardet
<stdin>: windows-1252 with confidence 0.73

Después de tener un buen candidato de juego de caracteres, podemos usar iconv, recodeo similar, para cambiar el juego de caracteres del archivo a su juego de caracteres "activo" (en mi caso, utf-8) y ver si adivinó correctamente ...

iconv -f windows-1252  -t utf-8 file

Algunos juegos de caracteres (como iso-8859-3, iso-8859-1) tienen muchos caracteres en común; a veces no es fácil ver si encontramos el juego de caracteres perfecto ...

Por lo tanto, es muy importante tener metadatos asociados con el texto relevante (por ejemplo, XML).

JJoao
fuente
Hmm No puedo reproducirlo aquí, simplemente se bloquea. Pero en cualquier caso, ¿no es eso simplemente decirme la codificación del archivo? Mi problema es identificar el carácter, no la codificación del archivo. Eso ya lo sabía.
terdon
1
Lo siento, no entendí la pregunta (mi problema habitual es identificar el juego de caracteres). si ahora la codificación, iconv -f ... -t utf-8 le mostrará los caracteres?
JJoao
No. Muestro la codificación allí mismo. Hubo un personaje en particular que no es compatible con esa codificación y es ese personaje que estaba tratando de identificar.
terdon
1
¡Iso-8859 no es la codificación! la codificación es iso-8850-1. iso-8859 es un estándar iso que incluye varias definiciones de chaset. Pruebafile -i ...
JJoao
1
@terdon, lamento insistir, pero todos los trucos que intentaste funcionan con el juego de caracteres correcto. Ej: iconv -f ISO-8859-1 -t UTF-8 file
JJoao
0
#!/bin/bash
#
# Search in a file, a known (part of a ) String (i.E.: Begrüßung),
# by testing all encodings
#
[[ $# -ne 2 ]] && echo "Usage: encoding-finder.sh FILE fUnKy_CHAR_FOR_SURE_IN_FILE" && exit
FILE=$1
PATTERN=$2
for enc in $( iconv -l | sed 's/..$//') 
do 
    iconv -f $enc -t UTF-8 $FILE  2>/dev/null | grep -m 1 $PATTERN && echo $enc 
done 

Si obtengo un archivo que contiene, por ejemplo, la palabra Begrung, puedo inferir que Begrüßung podría significar. Entonces lo convierto por todos los encodindgs conocidos y miro, si se encuentra uno, lo que lo convierte correctamente.

Por lo general, hay múltiples codificaciones que parecen encajar.

Para archivos más largos, puede cortar un fragmento en lugar de convertir cientos de páginas.

Entonces lo llamaría

encodingfinder.sh FILE Begrüßung

y el script prueba, ya sea convirtiéndolo con las codificaciones conocidas, cuál de ellos produce "Begrüßung".

Para encontrar tales personajes, menos suele ser de ayuda, ya que los personajes originales a menudo se destacan. Desde el contexto, generalmente se puede inferir la palabra correcta para buscar. Pero no queremos consultar con un editor hexadecimal, qué byte es este, y luego visitar interminables tablas de codificaciones, para encontrar a nuestro delincuente. :)

usuario desconocido
fuente