Comment identifier un personnage étrange?

10

J'essaie d'identifier un personnage étrange que j'ai trouvé dans un fichier avec lequel je travaille:

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

Le fichier utilise le codage ISO-8859 et ne peut pas être converti en 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

Ma principale question est de savoir comment puis-je interpréter la sortie d' odici? J'essaie d'utiliser cette page qui me permet de traduire entre différentes représentations de caractères, mais elle me dit qu'en 005353tant que "point de code hexadécimal" ce qui ne semble pas correct et en 0aebtant que "point de code hexadécimal" est ce qui, encore une fois, semble incorrect .

Alors, comment puis-je utiliser l'une des trois options ( 355, 005353ou 0aeb) pour savoir quel personnage ils sont censés représenter?

Et oui, j'ai essayé avec les outils Unicode mais il ne semble pas non plus être un caractère UTF valide:

$ 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 je comprends la description du caractère Unicode U + FFFD, ce n'est pas du tout un vrai caractère mais un espace réservé pour un caractère corrompu. Ce qui est logique puisque le fichier n'est pas réellement encodé en UTF-8.

terdon
la source
5
EB pourrait être δ dans la page de codes 437 , ou Ù dans la page de codes 850 , ou ë dans 8859-1 ; est-ce que tout cela aurait du sens? (se iconvplaint parce que vous n'avez pas spécifié le jeu de caractères source, il utilise donc votre valeur par défaut qui est probablement UTF-8.)
Stephen Kitt
@StephenKitt oui, ëc'est ce que je vois quand les données sont utilisées sur un autre programme! Mais comment puis-je le savoir? N'est-ce pas quelque part dans les données que je fournis? Comment avez-vous trouvé? Oh, j'avais essayé iconvavec -f ISO-8859mais il se plaignait de l' conversion from ISO-8859 «n'est pas pris en charge».
terdon
1
Argh! Je vois, je devais utiliser juste ebet ignorer l' 0xindicateur hexadécimal ou quoi que ce soit. Mon ignorance de ce genre de chose est profonde. Pourriez-vous poster une réponse expliquant que @StephenKitt?
terdon
5
Votre erreur cruciale ici est que ISO-8859 n'est pas le nom d'un encodage. C'est une famille d'encodages; apparemment, celui que vous recherchez est ISO-8859-1.
tripleee du
1
Ensuite, vous iconvauriez réussi; et / ou vous auriez pu le rechercher par exemple sur Wikipédia. Pour cet encodage très spécifique, fileformat.info/info/unicode/char/00eb/index.htm fonctionne également (Unicode est équivalent à ISO-8859-1 dans la gamme 128-255, bien que bien sûr aucun encodage UTF ne soit compatible avec lui ).
tripleee

Réponses:

22

Votre fichier contient deux octets, EB et 0A en hexadécimal. Il est probable que le fichier utilise un jeu de caractères avec un octet par caractère, tel que ISO-8859-1 ; dans ce jeu de caractères, EB est ë:

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

Les autres candidats seraient δ dans la page de code 437 , Ù dans la page de code 850 ...

od -xLa sortie de confuse dans ce cas en raison de l'endianité; une meilleure option est celle -t x1qui utilise des octets simples:

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

od -xles cartes od -t x2auxquelles lit deux octets à la fois, et sur les systèmes little-endian sortent les octets dans l'ordre inverse.

Lorsque vous rencontrez un fichier comme celui-ci, qui n'est pas UTF-8 valide (ou n'a aucun sens lorsqu'il est interprété comme un fichier UTF-8), il n'y a aucun moyen infaillible de déterminer automatiquement son encodage (et son jeu de caractères). Le contexte peut aider: s'il s'agit d'un fichier produit sur un PC occidental au cours des deux dernières décennies, il y a de fortes chances qu'il soit codé en ISO-8859-1, -15 (la variante Euro) ou Windows-1252; s'il est plus ancien que cela, les CP-437 et CP-850 sont probablement des candidats. Les fichiers des systèmes d'Europe de l'Est, des systèmes russes ou des systèmes asiatiques utiliseraient différents jeux de caractères que je ne connais pas beaucoup. Ensuite, il y a EBCDIC ... listera iconv -ltous les jeux de caractères connus iconv, et vous pouvez procéder par essais et erreurs à partir de là.

(À un moment donné, je connaissais par cœur la plupart des CP-437 et ATASCII, c'était l'époque.)

Stephen Kitt
la source
1
OK, dans la page wikipedia à laquelle vous accédez, je peux voir que cela ëest décrit comme 00EBet 234. Quels sont ces extra 00? Et pourquoi n'est-ce pas ce 355que j'attendais de la odsortie? J'essaie d'obtenir une réponse plus générale sur la façon dont je peux utiliser la odsortie pour identifier le personnage. Pourriez-vous peut-être expliquer quelque chose sur l'interprétation des codes hexadécimaux et / ou quelles informations sont nécessaires pour être en mesure d'identifier un caractère inconnu (encodage et autre)?
terdon
EB est 353 en octal (pas 355). Je vais essayer de généraliser ...
Stephen Kitt
Oups, désolé, je voulais dire 353. Le 353 est donc une représentation octale, pas décimale. Argh.
terdon
1
Oui, le «o» odsignifie octal ;-).
Stephen Kitt
1
Dans tous les cas, le (U + FFFD) serait affiché par l'émulateur de terminal en remplacement de cet octet 0xeb qui ne forme pas un caractère valide en UTF-8. On ne sait pas pourquoi uniprops $(cat file)(guillemets manquants btw) signalerait cela (je ne sais pas pour cette unipropscommande). unicode "$(cat file)"sur Debian produit Sequence '\xeb' is not valid in charset 'UTF-8'comme je m'y attendais.
Stéphane Chazelas
5

Notez que odc'est court pour le vidage octal , 005353les deux octets comme mot octal, od -xsont 0aeben hexadécimal comme mot, et le contenu réel de votre fichier est les deux octets ebet 0aen hexadécimal, dans cet ordre.

Donc, les deux 005353et 0aebne peuvent pas simplement être interprétés comme «point de code hexadécimal».

0aest un saut de ligne (LF) et ebdépend de votre encodage. fileest juste de deviner l'encodage, ça pourrait être n'importe quoi. Sans aucune autre information sur l'origine du fichier, etc., il sera difficile de le savoir.

dirkt
la source
Je me rends compte que c'est parce que je ne comprends pas comment fonctionnent les points de code (ou hex, vraiment), mais comment puis-je le savoir? J'utilise habituellement od -ccar cela produit une sortie que je peux comprendre. Comment aurais-je pu utiliser le 355qui produit pour identifier le personnage? Et pourquoi imprime-t-il 0aebau lieu de eb0asi 0aest la nouvelle ligne?
terdon
@terdon endianness ... Voir ma réponse mise à jour.
Stephen Kitt
2

Il est impossible de deviner avec 100% de précision le jeu de caractères des fichiers texte.

Des outils comme chardet , firefox , file -i quand aucune information explicite de jeu de caractères n'est définie (par exemple, si un HTML contient un méta jeu de caractères = ... dans la tête, les choses sont plus faciles) essaieront d'utiliser des heuristiques qui ne sont pas si mauvaises si le texte est assez gros.

Dans ce qui suit, je démontre la détection de charset avec chardet( pip install chardet/ apt-get install python-chardetsi nécessaire).

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

Après avoir un bon candidat de jeu de caractères, nous pouvons utiliser iconv, recodeou similaire, pour changer le fichier de caractères en votre jeu de caractères "actif" (dans mon cas utf-8) et voir s'il a bien deviné ...

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

Certains jeux de caractères (comme iso-8859-3, iso-8859-1) ont de nombreux caractères en commun - parfois, il n'est pas facile de voir si nous avons trouvé le jeu de caractères parfait ...

Il est donc très important d'avoir des métadonnées associées au texte pertinent (par exemple XML).

JJoao
la source
Hmm. Je ne peux pas le reproduire ici, ça plante juste. Mais en tout cas, cela ne me dit-il pas simplement l'encodage du fichier? Mon problème est d'identifier le caractère et non l'encodage du fichier. Que je savais déjà.
terdon
1
Désolé, je n'ai pas compris la question (mon problème habituel est d'identifier le jeu de caractères). si vous maintenant l'encodage, iconv -f ... -t utf-8 vous montrera les caractères?
JJoao
Non, je montre l'encodage juste là. Il y avait un caractère particulier non pris en charge par cet encodage et c'est ce caractère que j'essayais d'identifier.
terdon
1
L'ISO-8859 n'est pas l'encodage! l'encodage est iso-8850-1. iso-8859 est un standart iso qui inclut plusieurs définitions de chaset. Essayezfile -i ...
JJoao
1
@terdon, désolé d'insister, mais toutes les astuces que vous avez essayées fonctionnent avec le bon jeu de caractères. Ex: 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 j'obtiens un fichier qui contient, par exemple, le mot Begrung, je peux en déduire que Begrüßung pourrait être voulu. Je le convertis donc par tous les encodindgs connus et regarde, s'il y en a un, qui le convertit correctement.

Habituellement, il existe plusieurs encodages qui semblent correspondre.

Pour les fichiers plus longs, vous pouvez couper un extrait au lieu de convertir des centaines de pages.

Donc je l'appellerais

encodingfinder.sh FILE Begrüßung

et les tests de script, que ce soit en les convertissant avec les encodages connus, lesquels produisent "Begrüßung".

Pour trouver de tels personnages, moins est généralement utile, car les personnages funky se distinguent souvent. Du contexte, le bon mot à rechercher peut généralement être déduit. Mais nous ne voulons pas vérifier avec un hexeditor, de quel octet il s'agit, puis visiter des tables infinies d'encodages, pour trouver notre délinquant. :)

Utilisateur inconnu
la source