
Estou tentando identificar um caractere estranho que encontrei em um arquivo com o qual estou trabalhando:
$ cat file
�
$ od file
0000000 005353
0000002
$ od -c file
0000000 353 \n
0000002
$ od -x file
0000000 0aeb
0000002
O arquivo usa codificação ISO-8859 e não pode ser convertido para 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
Minha principal questão é como posso interpretar a saída daqui od
? estou tentando usaresta páginao que me permite traduzir entre diferentes representações de caracteres, mas me diz que 005353
como um "ponto de código hexadecimal" é 卓
o que não parece certo e 0aeb
como um "ponto de código hexadecimal" é ૫
o que, novamente, parece errado.
Então, como posso usar qualquer uma das três opções ( 355
, 005353
ou 0aeb
) para descobrir qual caractere elas deveriam representar?
E sim, tentei com ferramentas Unicode, mas também não parece ser um caractere 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
se bem entendi a descrição do caractere Unicode U + FFFD, ele não é um caractere real, mas um espaço reservado para um caractere corrompido. O que faz sentido, já que o arquivo não é realmente codificado em UTF-8.
Responder1
Seu arquivo contém dois bytes, EB e 0A em hexadecimal. É provável que o arquivo esteja usando um conjunto de caracteres com um byte por caractere, comoISO-8859-1; nesse conjunto de caracteres, EB é ë:
$ printf "\353\n" | iconv -f ISO-8859-1
ë
Outros candidatos seriam δ empágina de código 437, Ù empágina de código 850...
od -x
a saída de é confusa neste caso por causa do endianismo; uma opção melhor é -t x1
usar bytes únicos:
$ printf "\353\n" | od -t x1
0000000 eb 0a
0000002
od -x
mapeia para od -t x2
o qual lê dois bytes por vez e, em sistemas little-endian, gera os bytes na ordem inversa.
Quando você se depara com um arquivo como este, que não é UTF-8 válido (ou não faz sentido quando interpretado como um arquivo UTF-8), não há uma maneira infalível de determinar automaticamente sua codificação (e conjunto de caracteres). O contexto pode ajudar: se for um arquivo produzido em um PC ocidental nas últimas décadas, há uma boa chance de que esteja codificado em ISO-8859-1, -15 (a variante Euro) ou Windows-1252; se for mais antigo, CP-437 e CP-850 são prováveis candidatos. Arquivos de sistemas do Leste Europeu, ou sistemas russos, ou sistemas asiáticos, usariam diferentes conjuntos de caracteres sobre os quais não sei muito. Depois, há o EBCDIC... iconv -l
listará todos os conjuntos de caracteres que iconv
você conhece e você poderá prosseguir por tentativa e erro a partir daí.
(A certa altura eu sabia de cor a maior parte do CP-437 e ATASCII, eram os dias.)
Responder2
Observe que od
é uma abreviação dedespejo octal, assim 005353
como os dois bytes como palavra octal, od -x
está 0aeb
em hexadecimal como palavra, e o conteúdo real do seu arquivo são os dois bytes eb
e 0a
em hexadecimal, nesta ordem.
Portanto, ambos 005353
e 0aeb
não podem ser interpretados apenas como "ponto de código hexadecimal".
0a
é um feed de linha (LF) e eb
depende da sua codificação. file
está apenas adivinhando a codificação, pode ser qualquer coisa. Sem mais informações de onde veio o arquivo, etc., será difícil descobrir.
Responder3
É impossível adivinhar com 100% de precisão o conjunto de caracteres dos arquivos de texto.
Ferramentas comocharete,Raposa de fogo,arquivo -euquando não há informações explícitas de charset definidas (por exemplo, se um HTML contém um meta charset=... no cabeçalho, as coisas são mais fáceis) tentará usar heurísticas que não sejam tão ruins se o texto for grande o suficiente.
A seguir, demonstro a detecção de charset com chardet
( pip install chardet
/ apt-get install python-chardet
se necessário).
$ echo "in Noël" | iconv -f utf8 -t latin1 | chardet
<stdin>: windows-1252 with confidence 0.73
Depois de ter um bom candidato a charset, podemos usar iconv
, recode
ou similar para alterar o charset do arquivo para o seu charset "ativo" (no meu caso utf-8) e ver se acertou...
iconv -f windows-1252 -t utf-8 file
Alguns conjuntos de caracteres (como iso-8859-3, iso-8859-1) têm muitos caracteres em comum - às vezes não é fácil ver se encontramos o conjunto de caracteres perfeito...
Por isso é muito importante ter metadados associados a textos relevantes (por exemplo, XML).
Responder4
#!/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
Se eu obtiver um arquivo que contenha, por exemplo, a palavra Begrung, posso inferir que Begrüßung pode ser o significado. Então eu o converto por todas as codificações conhecidas e procuro se alguma foi encontrada, o que a converte corretamente.
Normalmente, existem várias codificações que parecem se encaixar.
Para arquivos mais longos, você pode cortar um trecho em vez de converter centenas de páginas.
Então eu chamaria isso
encodingfinder.sh FILE Begrüßung
e o script testa, seja convertendo-o com as codificações conhecidas, quais delas produzem "Begrüßung".
Para encontrar esses personagens, menos geralmente ajuda, já que personagens descolados geralmente se destacam. A partir do contexto, geralmente é possível inferir a palavra certa a ser pesquisada. Mas não queremos verificar com um editor hexadecimal que byte é esse e depois visitar infinitas tabelas de codificações para encontrar nosso agressor. :)