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 questão é como interpretar a saída de od aqui? Eu estou tentando usar esta página que me permite traduzir entre diferentes representações de personagem, mas ele me diz que 005353 como um "ponto de código hexadecimal" é , o que não parece certo e 0aeb como "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 personagem elas 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 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 é codificado em UTF-8.

    
por terdon 28.04.2017 / 14:58

4 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 "3\n" | iconv -f ISO-8859-1
ë

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

A saída de

od -x é confusa nesse caso por causa do endianness; uma opção melhor é -t x1 , que usa bytes únicos:

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

od -x mapeia para od -t x2 , que lê dois bytes por vez, e em sistemas little-endian, os bytes são exibidos 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á nenhuma maneira infalível para determinar automaticamente sua codificação (e conjunto de caracteres ). Contexto pode ajudar: se for um arquivo produzido em um PC ocidental nas últimas duas décadas, há uma boa chance de que ele esteja codificado em ISO-8859-1, -15 (a variante do Euro) ou Windows-1252; Se for mais antigo, o CP-437 e o CP-850 são candidatos prováveis. Arquivos de sistemas da Europa Oriental, ou sistemas russos ou asiáticos, usariam conjuntos de caracteres diferentes dos quais eu não sei muito. Em seguida, há EBCDIC ... iconv -l listará todos os conjuntos de caracteres que o iconv conhece e você pode prosseguir por tentativa e erro a partir daí.

(Em um ponto eu conhecia a maioria dos CP-437 e ATASCII de cor, eram os dias.)

    
por 28.04.2017 / 15:14
5

Observe que od é a abreviação de octal dump , portanto 005353 são os dois bytes como palavra octal, od -x é 0aeb em hexadecimal como palavra e o conteúdo real de seu arquivo são os dois bytes eb e 0a em hexadecimal, nesta ordem.

Portanto, 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 sobre onde o arquivo veio, etc., será difícil descobrir.

    
por 28.04.2017 / 15:11
2

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

Ferramentas como chardet , firefox , arquivo -i quando não há informações explícitas sobre conjuntos de caracteres definidas (por exemplo, se um HTML contém um meta charset = ... na cabeça, 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 caracteres 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 mudar o charset do arquivo para o seu charset "ativo" (no meu caso utf-8) e veja 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 ...

Por isso, é muito importante ter metadados associados a textos relevantes (por exemplo, XML).

    
por 28.04.2017 / 16:56
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 pegar um arquivo, que contém, por exemplo, o Word Begrung, posso inferir que Begrüßung pode ser usado. Então eu converto por todos os encodindgs conhecidos e procuro, se um é encontrado, o que converte corretamente.

Normalmente, existem várias codificações que parecem se encaixar.

Para arquivos maiores, você pode cortar um snippet em vez de converter centenas de páginas.

Então eu chamaria de

encodingfinder.sh FILE Begrüßung

e o script testa, seja convertendo-o com as codificações conhecidas, que produzem "Begrüßung".

Para encontrar esses personagens, menos geralmente é de ajuda, já que os personagens da moda geralmente se destacam. A partir do contexto, a palavra certa a ser pesquisada geralmente pode ser inferida. Mas nós não queremos verificar com um hexeditor, o que é isso, e então visitar tabelas intermináveis de codificações, para encontrar nosso ofensor. :)

    
por 08.03.2018 / 16:58