
Estoy tratando de identificar un carácter extraño que encontré 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 utiliza 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 el resultado de od
aquí? estoy tratando de usaresta páginalo que me permite traducir entre diferentes representaciones de caracteres, pero me dice que 005353
como "punto de código hexadecimal" es 卓
lo que no parece correcto y 0aeb
como "punto de código hexadecimal" es ૫
lo que, nuevamente, parece incorrecto.
Entonces, ¿cómo puedo usar cualquiera de las tres opciones ( 355
, 005353
o 0aeb
) para saber qué personaje se supone que representan?
Y sí, lo intenté 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 carácter Unicode U+FFFD, no es un carácter real sino un marcador de posición para un carácter corrupto. Lo cual tiene sentido ya que el archivo en realidad no está codificado en UTF-8.
Respuesta1
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, comoISO-8859-1; en ese conjunto de caracteres, EB es ë:
$ printf "\353\n" | iconv -f ISO-8859-1
ë
Otros candidatos serían δ enpágina de códigos 437, Ù enpágina de códigos 850...
od -x
La salida de es confusa en este caso debido a la endianidad; una mejor opción es -t x1
la que utiliza bytes únicos:
$ printf "\353\n" | od -t x1
0000000 eb 0a
0000002
od -x
mapas en od -t x2
los que lee dos bytes a la vez y, en sistemas little-endian, genera los bytes en orden inverso.
Cuando te encuentras con un archivo como este, que no es UTF-8 válido (o no tiene sentido cuando se interpreta como un archivo UTF-8), no existe 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, es muy probable que esté codificado en ISO-8859-1, -15 (la variante europea) o Windows-1252; si es más antiguo, CP-437 y CP-850 son candidatos probables. Los archivos de sistemas de Europa del Este, de sistemas rusos o de sistemas asiáticos usarían diferentes conjuntos de caracteres de los que no sé mucho. Luego está EBCDIC... iconv -l
enumerará todos los conjuntos de caracteres que iconv
conoce y podrá proceder mediante prueba y error desde allí.
(En un momento me sabía de memoria la mayor parte de CP-437 y ATASCII, esos eran los días).
Respuesta2
Tenga en cuenta que od
es la abreviatura devolcado octal, también lo 005353
son los dos bytes como palabra octal, od -x
está 0aeb
en hexadecimal como palabra, y el contenido real de su archivo son los dos bytes eb
y 0a
en hexadecimal, en este orden.
Por lo tanto, ambos 005353
y 0aeb
no pueden interpretarse simplemente como "puntos de código hexadecimal".
0a
es un avance de línea (LF) y eb
depende de su codificación. file
Es solo adivinar la codificación, podría ser cualquier cosa. Sin más información de dónde proviene el archivo, etc., será difícil averiguarlo.
Respuesta3
Es imposible adivinar con un 100% de precisión el juego de caracteres de los archivos de texto.
Herramientas comochardet,firefox,archivo -yocuando no hay información explícita del juego de caracteres definida (por ejemplo, si un HTML contiene un meta juego de caracteres=... en el encabezado, las cosas son más fáciles) intentará usar heurísticas que no son tan malas si el texto es lo suficientemente grande.
A continuación, demuestro la detección de juegos de caracteres con chardet
( pip install chardet
/ apt-get install python-chardet
si 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 conjunto de caracteres candidato, podemos usar iconv
, recode
o similar, para cambiar el conjunto de caracteres del archivo a su conjunto de caracteres "activo" (en mi caso, utf-8) y ver si adivinó correctamente...
iconv -f windows-1252 -t utf-8 file
Algunos conjuntos 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 conjunto de caracteres perfecto...
Por eso es muy importante tener metadatos asociados con el texto relevante (por ejemplo, XML).
Respuesta4
#!/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 podría referirse a Begrüßung. Así que lo convierto con todas las codificaciones conocidas y miro si se encuentra alguna que lo convierta correctamente.
Por lo general, existen múltiples codificaciones que parecen encajar.
Para archivos más largos, puedes cortar un fragmento en lugar de convertir cientos de páginas.
Entonces yo lo llamaría
encodingfinder.sh FILE Begrüßung
y el script prueba, mediante conversión con las codificaciones conocidas, cuál de ellas produce "Begrüßung".
Para encontrar tales personajes, normalmente menos ayuda, ya que los personajes originales a menudo destacan. A partir del contexto, normalmente se puede inferir la palabra correcta a buscar. Pero no queremos comprobar con un editor hexadecimal qué byte es este y luego visitar infinitas tablas de codificaciones para encontrar a nuestro infractor. :)