Au travail, il semble qu'aucune semaine ne passe sans une conniption, une calamité ou une catastrophe liées à l'encodage. Le problème vient généralement des programmeurs qui pensent pouvoir traiter de manière fiable un fichier «texte» sans spécifier l'encodage. Mais tu ne peux pas.
Il a donc été décidé d'interdire désormais aux fichiers d'avoir des noms qui se terminent par *.txt
ou *.text
. L'idée est que ces extensions induisent en erreur le programmeur occasionnel dans une complaisance sourde concernant les encodages, ce qui conduit à une mauvaise manipulation. Il serait presque préférable de ne pas avoir d'extension du tout, car au moins, vous savez que vous ne savez pas ce que vous avez.
Cependant, nous ne sommes pas prêts à aller aussi loin. À la place, vous devrez utiliser un nom de fichier qui se termine par le codage. Donc , pour les fichiers texte, par exemple, ce serait quelque chose comme README.ascii
, README.latin1
, README.utf8
, etc.
Pour les fichiers qui nécessitent une extension particulière, si l'on peut spécifier le codage à l'intérieur du fichier lui-même, comme en Perl ou Python, alors vous devez le faire. Pour les fichiers comme Java source où aucune fonctionnalité de ce type n'existe à l'intérieur du fichier, vous placerez l'encodage avant l'extension, par exemple SomeClass-utf8.java
.
Pour la sortie, UTF-8 doit être fortement préféré.
Mais pour entrer, nous devons comprendre comment gérer les milliers de fichiers nommés dans notre base de code *.txt
. Nous voulons tous les renommer pour qu'ils correspondent à notre nouvelle norme. Mais nous ne pouvons pas tous les observer. Nous avons donc besoin d'une bibliothèque ou d'un programme qui fonctionne réellement.
Ceux-ci sont différents en ASCII, ISO-8859-1, UTF-8, Microsoft CP1252 ou Apple MacRoman. Bien que nous sachions que nous pouvons dire si quelque chose est ASCII, et que nous sommes un bon changement de savoir si quelque chose est probablement UTF-8, nous sommes perplexes au sujet des encodages 8 bits. Parce que nous fonctionnons dans un environnement Unix mixte (Solaris, Linux, Darwin) avec la plupart des bureaux étant des Mac, nous avons pas mal de fichiers MacRoman ennuyeux. Et ceux-ci sont particulièrement problématiques.
Depuis un certain temps, je cherche un moyen de déterminer par programme lequel des
- ASCII
- ISO-8859-1
- CP1252
- MacRoman
- UTF-8
il y a un fichier et je n'ai pas trouvé de programme ou de bibliothèque capable de distinguer de manière fiable les trois encodages 8 bits différents. Nous avons probablement plus d'un millier de fichiers MacRoman à eux seuls, donc quel que soit le détecteur de jeu de caractères que nous utilisons, il doit être capable de les détecter. Rien de ce que j'ai regardé ne peut gérer le truc. J'avais de grands espoirs pour la bibliothèque de détecteurs de charset ICU , mais elle ne peut pas gérer MacRoman. J'ai aussi regardé des modules pour faire le même genre de chose en Perl et Python, mais encore et encore c'est toujours la même histoire: pas de support pour la détection de MacRoman.
Ce que je recherche donc, c'est une bibliothèque ou un programme existant qui détermine de manière fiable dans lequel de ces cinq encodages se trouve un fichier - et de préférence plus que cela. En particulier, il doit faire la distinction entre les trois encodages 3 bits que j'ai cités, en particulier MacRoman . Les fichiers sont à plus de 99% de texte en anglais; il y en a quelques-uns dans d'autres langues, mais pas beaucoup.
S'il s'agit de code de bibliothèque, notre préférence de langage est qu'il soit en Perl, C, Java ou Python, et dans cet ordre. S'il ne s'agit que d'un programme, alors nous ne nous soucions pas vraiment de la langue dans laquelle il se trouve tant qu'il est livré dans son intégralité, qu'il fonctionne sous Unix et qu'il est totalement libre.
Quelqu'un d'autre a-t-il eu ce problème d'un zillion de fichiers texte hérités encodés au hasard? Si oui, comment avez-vous tenté de le résoudre et dans quelle mesure avez-vous réussi? C'est l'aspect le plus important de ma question, mais je suis également intéressé à savoir si vous pensez qu'encourager les programmeurs à nommer (ou renommer) leurs fichiers avec l'encodage réel de ces fichiers nous aidera à éviter le problème à l'avenir. Quelqu'un a-t-il déjà essayé d'appliquer cela sur une base institutionnelle, et si oui, cela a-t-il réussi ou non, et pourquoi?
Et oui, je comprends parfaitement pourquoi on ne peut garantir une réponse définitive étant donné la nature du problème. C'est particulièrement le cas avec les petits fichiers, où vous ne disposez pas de suffisamment de données pour continuer. Heureusement, nos fichiers sont rarement petits. Mis à part le README
fichier aléatoire , la plupart ont une taille comprise entre 50k et 250k, et beaucoup sont plus grands. Tout ce qui dépasse quelques K est garanti en anglais.
Le domaine du problème est l'exploration de texte biomédicale, nous avons donc parfois affaire à des corpus étendus et extrêmement volumineux, comme tout le référentiel Open Access de PubMedCentral. Un fichier assez volumineux est le BioThesaurus 6.0, à 5,7 gigaoctets. Ce fichier est particulièrement ennuyeux car il est presque entièrement en UTF-8. Cependant, certains numbskull y sont allés et y ont collé quelques lignes qui sont dans un encodage 8 bits - Microsoft CP1252, je crois. Cela prend un certain temps avant de vous lancer sur celui-là. :(
Réponses:
Tout d'abord, les cas faciles:
ASCII
Si vos données ne contiennent pas d'octets au-dessus de 0x7F, c'est ASCII. (Ou un encodage ISO646 7 bits, mais ceux-ci sont très obsolètes.)
UTF-8
Si vos données sont valides en UTF-8, vous pouvez supposer en toute sécurité qu'il s'agit de UTF-8. En raison des règles de validation strictes de l'UTF-8, les faux positifs sont extrêmement rares.
ISO-8859-1 contre Windows-1252
La seule différence entre ces deux encodages est que ISO-8859-1 a les caractères de contrôle C1 où windows-1252 a les caractères imprimables € ‚ƒ„… † ‡ ˆ ‰ Š ‹ŒŽ ''“ ”• –—˜ ™ š› œžŸ. J'ai vu beaucoup de fichiers qui utilisent des guillemets ou des tirets, mais aucun n'utilise des caractères de contrôle C1. Alors ne vous embêtez même pas avec eux, ou ISO-8859-1, détectez simplement windows-1252 à la place.
Cela ne vous laisse plus qu'une seule question.
Comment distinguez-vous MacRoman de cp1252?
C'est beaucoup plus délicat.
Caractères non définis
Les octets 0x81, 0x8D, 0x8F, 0x90, 0x9D ne sont pas utilisés dans Windows-1252. S'ils se produisent, supposez que les données sont MacRoman.
Caractères identiques
Les octets 0xA2 (¢), 0xA3 (£), 0xA9 (©), 0xB1 (±), 0xB5 (µ) se trouvent être les mêmes dans les deux encodages. Si ce sont les seuls octets non ASCII, peu importe que vous choisissiez MacRoman ou cp1252.
Approche statistique
Comptez les fréquences de caractères (PAS d'octets!) Dans les données que vous savez être UTF-8. Déterminez les caractères les plus fréquents. Utilisez ensuite ces données pour déterminer si les caractères cp1252 ou MacRoman sont plus courants.
Par exemple, dans une recherche que je viens d'effectuer sur 100 articles Wikipedia anglais aléatoires, les caractères non ASCII les plus courants sont
·•–é°®’èö—
. Sur la base de ce fait,Comptez les octets suggérant cp1252 et les octets suggérant MacRoman, et choisissez celui qui est le plus grand.
la source
Mozilla nsUniversalDetector (liaisons Perl: Encode :: Detect / Encode :: Detect :: Detector ) est prouvé des millions de fois.
la source
x-mac-cyrillic
est pris en charge,x-mac-hebrew
est discuté en détail dans les commentaires,x-mac-anything-else
ne reçoit pas de mention.Ma tentative d'une telle heuristique (en supposant que vous ayez exclu ASCII et UTF-8):
Note latérale:
Ne faites pas cela!!
Le compilateur Java s'attend à ce que les noms de fichiers correspondent aux noms de classe, donc renommer les fichiers rendra le code source non compilable. La bonne chose serait de deviner l'encodage, puis d'utiliser l'
native2ascii
outil pour convertir tous les caractères non ASCII en séquences d'échappement Unicode .la source
*.text
fichiers."Perl, C, Java ou Python, et dans cet ordre": attitude intéressante :-)
«Nous avons un bon changement de savoir si quelque chose est probablement UTF-8»: En fait, la chance qu'un fichier contenant du texte significatif encodé dans un autre jeu de caractères qui utilise des octets à haut bit soit décodé avec succès car UTF-8 est extrêmement petit.
Stratégies UTF-8 (dans la langue la moins préférée):
Une fois que vous avez décidé que ce n'est ni ASCII ni UTF-8:
Les détecteurs de jeux de caractères d'origine Mozilla que je connais ne prennent pas en charge MacRoman et ne font en aucun cas un bon travail sur les jeux de caractères 8 bits, en particulier avec l'anglais, car ils dépendent de vérifier si le décodage a du sens dans le langue, ignorant les caractères de ponctuation et basée sur une large sélection de documents dans cette langue.
Comme d'autres l'ont fait remarquer, vous ne disposez en réalité que des caractères de ponctuation à jeu de bits élevé pour faire la distinction entre cp1252 et macroman. Je suggérerais de former un modèle de type Mozilla sur vos propres documents, pas Shakespeare ou Hansard ou la Bible KJV, et en tenant compte des 256 octets. Je suppose que vos fichiers ne contiennent aucun balisage (HTML, XML, etc.) - cela déformerait les probabilités, quelque chose de choquant.
Vous avez mentionné des fichiers qui sont pour la plupart UTF-8 mais qui ne parviennent pas à décoder. Vous devez également être très méfiant envers:
(1) fichiers qui sont prétendument encodés en ISO-8859-1 mais contiennent des "caractères de contrôle" dans la plage 0x80 à 0x9F inclus ... ceci est si répandu que le projet de norme HTML5 dit de décoder TOUS les flux HTML déclarés comme ISO-8859 -1 en utilisant cp1252.
(2) fichiers qui décodent OK comme UTF-8 mais l'Unicode résultant contient des "caractères de contrôle" dans la plage U + 0080 à U + 009F inclus ... cela peut résulter du transcodage cp1252 / cp850 (vu cela se produire!) / Etc fichiers de "ISO-8859-1" à UTF-8.
Contexte: J'ai un projet humide-dimanche après-midi pour créer un détecteur de jeu de caractères basé sur Python qui est orienté fichier (au lieu d'être orienté Web) et fonctionne bien avec les jeux de caractères 8 bits, y compris
legacy ** n
ceux comme cp850 et cp437. C'est encore loin d'être aux heures de grande écoute. Je suis intéressé par les fichiers de formation; Vos fichiers ISO-8859-1 / cp1252 / MacRoman sont-ils aussi "libres" que vous vous attendez à ce que la solution de code de quiconque soit?la source
Comme vous l'avez découvert, il n'y a pas de moyen parfait de résoudre ce problème, car sans la connaissance implicite du codage utilisé par un fichier, tous les codages 8 bits sont exactement les mêmes: une collection d'octets. Tous les octets sont valides pour tous les encodages 8 bits.
Le mieux que vous puissiez espérer, c'est une sorte d'algorithme qui analyse les octets, et basé sur les probabilités d'un certain octet utilisé dans une certaine langue avec un certain encodage, devinera quel encodage les fichiers utilisent. Mais cela doit savoir quelle langue le fichier utilise et devient complètement inutile lorsque vous avez des fichiers avec des encodages mixtes.
Par contre, si vous savez que le texte d'un fichier est écrit en anglais, il est peu probable que vous remarquiez une différence quel que soit le codage que vous décidez d'utiliser pour ce fichier, car les différences entre tous les codages mentionnés sont toutes localisées dans les parties des encodages qui spécifient des caractères normalement non utilisés en anglais. Vous pourriez avoir des problèmes lorsque le texte utilise un formatage spécial, ou des versions spéciales de ponctuation (CP1252 a plusieurs versions des caractères de guillemet par exemple), mais pour l'essentiel du texte, il n'y aura probablement aucun problème.
la source
Si vous pouvez détecter tous les encodages SAUF pour macroman, il serait logique de supposer que ceux qui ne peuvent pas être déchiffrés sont en macroman. En d'autres termes, faites simplement une liste des fichiers qui n'ont pas pu être traités et gérez-les comme s'ils étaient macroman.
Une autre façon de trier ces fichiers serait de créer un programme basé sur un serveur permettant aux utilisateurs de décider quel encodage n'est pas brouillé. Bien sûr, ce serait au sein de l'entreprise, mais avec 100 employés qui en font quelques-uns chaque jour, vous aurez des milliers de fichiers traités en un rien de temps.
Enfin, ne serait-il pas préférable de simplement convertir tous les fichiers existants dans un seul format et d'exiger que les nouveaux fichiers soient dans ce format.
la source
J'écris actuellement un programme qui traduit des fichiers en XML. Il doit détecter automatiquement le type de chaque fichier, ce qui est un sur-ensemble du problème de la détermination du codage d'un fichier texte. Pour déterminer le codage, j'utilise une approche bayésienne. Autrement dit, mon code de classification calcule une probabilité (probabilité) qu'un fichier texte ait un codage particulier pour tous les codages qu'il comprend. Le programme sélectionne alors le décodeur le plus probable. L'approche bayésienne fonctionne comme ceci pour chaque encodage.
Il apparaît que Bayes théorème devient très facile à faire si au lieu de calcul des probabilités, vous calculer le contenu de l' information , qui est le logarithme des chances :
info = log(p / (1.0 - p))
.Vous devrez calculer la probabilité initail priori, et les corrélations, en examinant un corpus de fichiers que vous avez classifié manuellement.
la source