Como posso identificar um personagem estranho?

10

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 está usando a codificação ISO-8859 e não pode ser convertido em 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 pergunta é como posso interpretar a saída oddaqui? Estou tentando usar esta página que me permite traduzir entre diferentes representações de caracteres, mas ele me diz que 005353como um "ponto de código hexadecimal" é o que não parece certo e 0aebcomo um "ponto de código hexadecimal" é o que, novamente, parece errado .

Então, como posso usar qualquer uma das três opções ( 355, 005353ou 0aeb) para descobrir qual personagem eles devem 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 eu entendo 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.

terdon
fonte
5
EB pode ser δ na página de código 437 ou ’na página de código 850 ou ë em 8859-1 ; algum desses faria sentido? ( iconvReclama porque você não especificar o conjunto de caracteres de origem, para que ele usa o padrão que provavelmente é UTF-8.)
Stephen Kitt
@StephenKitt sim, ëé o que vejo quando os dados são usados ​​em outro programa! Mas como eu sei disso? Não está em algum lugar nos dados que forneço? Como você encontrou isso? Oh eu tinha tentado iconvcom -f ISO-8859mas reclamou conversion from ISO-8859' não é supported`.
terdon
1
Argh! Entendo, eu precisava usar justamente ebe ignorar o 0xindicador hexadecimal ou o que quer que seja. Minha ignorância desse tipo de coisa é profunda. Você poderia postar uma resposta explicando que @StephenKitt?
terdon
5
Seu erro crucial aqui é que ISO-8859 não é o nome de uma codificação. É uma família de codificações; aparentemente, o que você está procurando é o ISO-8859-1.
tripleee
1
Então o seu iconvteria conseguido; e / ou você poderia ter procurado, por exemplo, na Wikipedia. Para essa codificação muito específica, fileformat.info/info/unicode/char/00eb/index.htm também funciona (o Unicode é equivalente à ISO-8859-1 no intervalo 128-255, embora, obviamente, nenhuma codificação UTF seja compatível com ela. )
tripleee

Respostas:

22

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, como ISO-8859-1 ; nesse conjunto de caracteres, EB é ë:

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

Outros candidatos seriam δ na página de código 437 , Ù na página de código 850 ...

od -xa saída de é confusa neste caso por causa de endianness; uma opção melhor é -t x1usar bytes únicos:

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

od -xmapas para os od -t x2quais lê dois bytes de cada vez, e em sistemas little-endian emite os bytes na ordem inversa.

Quando você se deparar com um arquivo como este, que não é válido UTF-8 (ou não faz sentido quando interpretado como um arquivo UTF-8), não há 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 duas décadas, é bem provável que ele seja codificado nas normas ISO-8859-1, -15 (a variante Euro) ou Windows-1252; se for mais antigo, CP-437 e CP-850 provavelmente serão candidatos. Arquivos de sistemas da Europa Oriental ou russos ou asiáticos usariam diferentes conjuntos de caracteres que eu não conheço muito. Depois, há o EBCDIC ... iconv -llistará todos os conjuntos de caracteres que você iconvconhece e você pode prosseguir por tentativa e erro a partir daí.

(A certa altura, eu sabia a maior parte do CP-437 e ATASCII de cor, eram os dias.)

Stephen Kitt
fonte
1
OK, na página da wikipedia à qual você vincula, vejo que ëé descrito como 00EBe 234. Quais são esses extras 00? E por que não é 355como eu esperava da odsaída? Estou tentando obter uma resposta mais geral sobre como posso usar a odsaída para identificar o personagem. Você poderia explicar algo sobre a interpretação de códigos hexadecimais e / ou quais informações são necessárias para poder identificar um caractere desconhecido (codificação e qualquer outra coisa)?
terdon
EB é 353 em octal (não em 355). Vou tentar generalizar ...
Stephen Kitt
Opa, desculpe, eu quis dizer 353. Portanto, o 353 é uma representação octal, não decimal. Argh.
terdon
1
Sim, o "o" odsignifica octal ;-).
Stephen Kitt
1
De qualquer forma, o (U + FFFD) seria exibido pelo emulador de terminal como um substituto para o byte de 0xeb que não forma um caractere válido no UTF-8. Não está claro por que uniprops $(cat file)(aspas ausentes) reportaria isso (não sei sobre esse unipropscomando). unicode "$(cat file)"no Debian sai Sequence '\xeb' is not valid in charset 'UTF-8'como eu esperaria.
Stéphane Chazelas
5

Observe que odé abreviação de despejo octal , assim 005353como os dois bytes como palavra octal, od -xestá 0aebem hexadecimal como palavra e o conteúdo real do seu arquivo são os dois bytes ebe 0aem hexadecimal, nesta ordem.

Portanto, ambos 005353e 0aebnão podem ser interpretados como "ponto de código hexadecimal".

0aé um feed de linha (LF) e ebdepende da sua codificação. fileé apenas adivinhar a codificação, poderia ser qualquer coisa. Sem mais informações de onde o arquivo veio, etc., será difícil descobrir.

dirkt
fonte
Sei que é porque não entendo como os pontos de código (ou hexadecimais, na verdade) funcionam, mas como posso saber isso? Eu costumo usar od -cdesde que produz saída que eu possa entender. Como eu poderia ter usado o 355que produz para identificar o personagem? E por que está imprimindo em 0aebvez de eb0ase 0aé a nova linha?
terdon
@terdon endianness ... Veja minha resposta atualizada.
Stephen Kitt
2

É impossível adivinhar com 100% de precisão o conjunto de arquivos de texto.

Ferramentas como chardet , firefox , file -i quando não há informações explícitas sobre charset definidas (por exemplo, se um HTML contém um meta charset = ... na cabeça, as coisas são mais fáceis) tentarão usar heurísticas que não são tão ruins se o texto é grande o suficiente.

A seguir, demonstro a detecção de conjunto de caracteres com chardet( pip install chardet/ apt-get install python-chardetse 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, recodeou similar, para alterar o charset de arquivo para o seu charset "ativo" (no meu caso, utf-8) e ver se ele adivinhou corretamente ...

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

Alguns charset (como iso-8859-3, iso-8859-1) têm muitos caracteres em comum - às vezes não é fácil ver se encontramos o charset perfeito ...

Portanto, é muito importante ter metadados associados ao texto relevante (por exemplo, XML).

JJoao
fonte
Hmm. Não consigo reproduzi-lo aqui, apenas trava. Mas, de qualquer forma, isso não está simplesmente me dizendo a codificação do arquivo? Meu problema é identificar o caractere e não a codificação do arquivo. Isso eu já sabia.
terdon
1
Desculpe, não entendi a pergunta (meu problema usual é identificar o conjunto de caracteres). se você agora a codificação, iconv -f ... -t utf-8 mostrará os caracteres?
JJoao
Não. Eu mostro a codificação ali. Havia um caractere em particular não suportado por essa codificação e é esse caractere que eu estava tentando identificar.
terdon
1
Iso-8859 não é a codificação! a codificação é iso-8850-1. iso-8859 é um padrão iso que inclui várias definições de chaset. Tentefile -i ...
JJoao 28/04
1
@terdon, desculpe insistir, mas todos os truques que você tentou trabalhar com o conjunto de caracteres correto. Ex: iconv -f ISO-8859-1 -t UTF-8 file
JJoao 28/04
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 

Se eu receber um arquivo, que contém, para Instância, o Word Begrung, posso deduzir que Begrüßung pode estar relacionado. Então, eu o converto por todas as codificações conhecidas e veja se um deles foi encontrado, o que o converte corretamente.

Geralmente, 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, convertendo-o com as codificações conhecidas, quais delas produzem "Begrüßung".

Para encontrar esses personagens, geralmente menos ajuda, já que os personagens descolados geralmente se destacam. No contexto, a palavra certa a ser pesquisada geralmente pode ser inferida. Mas não queremos verificar com um hexeditor qual é o byte e visitar inúmeras tabelas de codificações para encontrar nosso ofensor. :)

Usuário desconhecido
fonte