Comment puis-je détecter l'encodage/codepage d'un fichier texte

dans notre application, nous recevons des fichiers textes ( .txt , .csv , etc.) provenant de sources diverses. Lors de la lecture, ces fichiers contiennent parfois des déchets, parce que les fichiers ont été créés dans une page de code différente/inconnue.

y a-t-il un moyen (automatique) de détecter la page codée d'un fichier texte?

le detectEncodingFromByteOrderMarks , sur le StreamReader constructeur, travaille pour UTF8 et d'autres fichiers unicode marqués, mais je cherche un moyen de détecter les pages de code, comme ibm850 , windows1252 .


Merci pour vos réponses, c'est ce que j'ai fait.

les fichiers que nous recevons sont des utilisateurs finaux, ils n'ont pas la moindre idée des codepages. Les récepteurs sont aussi des utilisateurs finaux, c'est désormais ce qu'ils savent des codepages: les Codepages existent, et sont gênants.

Solution:

  • ouvert le fichier reçu dans Notepad, regardez un morceau de texte brouillé. Si Quelqu'un s'appelle François ou quelque chose comme ça, avec ton intelligence humaine, tu peux deviner ça.
  • j'ai créé une petite application que l'utilisateur peut utiliser pour ouvrir le fichier et saisissez un texte que l'utilisateur sait qu'il apparaît dans le fichier, la page de codes correct est utilisé.
  • boucle toutes les codepages, et afficher ceux qui donnent une solution avec le texte fourni par l'utilisateur.
  • si plus d'une page de code apparaît, demandez à l'utilisateur de spécifier plus de texte.
278
demandé sur james.garriss 2008-09-18 12:02:35

20 réponses

vous ne pouvez pas détecter l'infiltration de code, vous devez lui dire. Vous pouvez analyser les octets et le deviner, mais cela peut donner des résultats bizarres (parfois amusants). Je ne peux pas le trouver maintenant, mais je suis sûr que Notepad peut être piégé en affichant du texte anglais en chinois.

quoi qu'il en soit, c'est ce que vous devez lire: le Minimum absolu chaque développeur de logiciel absolument, positivement doit savoir sur Unicode et les jeux de caractères (pas D'Excuses!) .

spécifiquement Joel dit:

Le Facteur Le Plus Important À Propos Des Encodages

si vous oubliez complètement tout ce que je viens d'expliquer, s'il vous plaît rappelez-vous un fait extrêmement important. Il ne fait pas de sens d'avoir une chaîne sans savoir quel encodage il utilise. Vous ne pouvez plus vous enfoncer la tête dans le sable et prétendre que le texte "simple" est ASCII. Il N'y a pas une Telle Chose Comme Texte Brut.

Si vous avez une chaîne, dans la mémoire, dans un fichier, ou dans un message électronique, vous devez savoir de quel encodage il est dans ou vous ne pouvez pas l'interpréter ou l'afficher correctement à l'utilisateur.

252
répondu JV. 2013-07-11 08:12:59

si vous cherchez à détecter des encodages non-UTF (c.-à-d. pas de BOM), vous êtes essentiellement à l'heuristique et l'analyse statistique du texte. Vous voudrez peut-être jeter un coup d'oeil au papier Mozilla sur la détection universelle de charset ( même lien, avec un meilleur formatage via la Machine de Wayback ).

30
répondu Tomer Gabel 2016-09-09 17:25:01

Avez-vous essayé C# port pour Mozilla jeu de caractères Universel Détecteur de

exemple de http://code.google.com/p/ude /

public static void Main(String[] args)
{
    string filename = args[0];
    using (FileStream fs = File.OpenRead(filename)) {
        Ude.CharsetDetector cdet = new Ude.CharsetDetector();
        cdet.Feed(fs);
        cdet.DataEnd();
        if (cdet.Charset != null) {
            Console.WriteLine("Charset: {0}, confidence: {1}", 
                 cdet.Charset, cdet.Confidence);
        } else {
            Console.WriteLine("Detection failed.");
        }
    }
}    
20
répondu ITmeze 2012-07-23 10:47:38

Vous ne pouvez pas détecter la page de codes

C'est clairement faux. Chaque navigateur web dispose d'une sorte de détecteur universel de caractères pour traiter les pages qui n'ont aucune indication d'un encodage. Firefox en a un. Vous pouvez télécharger le code et voir comment il fonctionne. Voir la documentation ici . Fondamentalement, il est une heuristique, mais qui fonctionne vraiment bien.

Compte tenu d'une quantité raisonnable de texte, il est même possible de détecter la langue.

voici un autre je viens de trouver en utilisant Google:

15
répondu shoosh 2014-03-08 17:30:48

je sais qu'il est très tard pour cette question et que cette solution ne plaira pas à certains (à cause de son parti pris anglais et de son manque de tests statistiques/empiriques), mais elle a très bien fonctionné pour moi, surtout pour le traitement des données CSV téléchargées:

http://www.architectshack.com/TextFileEncodingDetector.ashx

avantages:

  • de la NOMENCLATURE de détection intégré
  • Défaut/de secours d'encodage personnalisable
  • assez fiable (d'après mon expérience) pour les fichiers basés en Europe occidentale contenant des données exotiques (par exemple des noms français) avec un mélange de fichiers UTF-8 et de type Latin-1-essentiellement la plupart des environnements américains et d'Europe occidentale.

Note: c'est moi qui ai écrit cette classe, alors évidemment, prenez-la avec un grain de sel! :)

8
répondu Tao 2011-04-29 09:20:17

Notepad++ a cette caractéristique hors-de-la-boîte. Il est également favorable à sa modification.

7
répondu hegearon 2010-12-18 00:10:35

à la recherche d'une solution différente, j'ai trouvé que

https://code.google.com/p/ude /

cette solution est un peu lourde.

j'avais besoin d'une détection de codage de base, basée sur 4 premiers octets et probablement une détection de charset xml - donc j'ai pris un peu de code source d'internet et j'ai ajouté une version légèrement modifiée de

http://lists.w3.org/Archives/Public/www-validator/2002Aug/0084.html

écrit pour Java.

    public static Encoding DetectEncoding(byte[] fileContent)
    {
        if (fileContent == null)
            throw new ArgumentNullException();

        if (fileContent.Length < 2)
            return Encoding.ASCII;      // Default fallback

        if (fileContent[0] == 0xff
            && fileContent[1] == 0xfe
            && (fileContent.Length < 4
                || fileContent[2] != 0
                || fileContent[3] != 0
                )
            )
            return Encoding.Unicode;

        if (fileContent[0] == 0xfe
            && fileContent[1] == 0xff
            )
            return Encoding.BigEndianUnicode;

        if (fileContent.Length < 3)
            return null;

        if (fileContent[0] == 0xef && fileContent[1] == 0xbb && fileContent[2] == 0xbf)
            return Encoding.UTF8;

        if (fileContent[0] == 0x2b && fileContent[1] == 0x2f && fileContent[2] == 0x76)
            return Encoding.UTF7;

        if (fileContent.Length < 4)
            return null;

        if (fileContent[0] == 0xff && fileContent[1] == 0xfe && fileContent[2] == 0 && fileContent[3] == 0)
            return Encoding.UTF32;

        if (fileContent[0] == 0 && fileContent[1] == 0 && fileContent[2] == 0xfe && fileContent[3] == 0xff)
            return Encoding.GetEncoding(12001);

        String probe;
        int len = fileContent.Length;

        if( fileContent.Length >= 128 ) len = 128;
        probe = Encoding.ASCII.GetString(fileContent, 0, len);

        MatchCollection mc = Regex.Matches(probe, "^<\?xml[^<>]*encoding[ \t\n\r]?=[\t\n\r]?['\"]([A-Za-z]([A-Za-z0-9._]|-)*)", RegexOptions.Singleline);
        // Add '[0].Groups[1].Value' to the end to test regex

        if( mc.Count == 1 && mc[0].Groups.Count >= 2 )
        {
            // Typically picks up 'UTF-8' string
            Encoding enc = null;

            try {
                enc = Encoding.GetEncoding( mc[0].Groups[1].Value );
            }catch (Exception ) { }

            if( enc != null )
                return enc;
        }

        return Encoding.ASCII;      // Default fallback
    }

il suffit de lire probablement les premiers 1024 octets du fichier, mais je charge le fichier entier.

7
répondu TarmoPikaro 2013-10-19 16:23:31

si quelqu'un cherche une solution à 93,9%. Cela me convient:

public static class StreamExtension
{
    /// <summary>
    /// Convert the content to a string.
    /// </summary>
    /// <param name="stream">The stream.</param>
    /// <returns></returns>
    public static string ReadAsString(this Stream stream)
    {
        var startPosition = stream.Position;
        try
        {
            // 1. Check for a BOM
            // 2. or try with UTF-8. The most (86.3%) used encoding. Visit: http://w3techs.com/technologies/overview/character_encoding/all/
            var streamReader = new StreamReader(stream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true), detectEncodingFromByteOrderMarks: true);
            return streamReader.ReadToEnd();
        }
        catch (DecoderFallbackException ex)
        {
            stream.Position = startPosition;

            // 3. The second most (6.7%) used encoding is ISO-8859-1. So use Windows-1252 (0.9%, also know as ANSI), which is a superset of ISO-8859-1.
            var streamReader = new StreamReader(stream, Encoding.GetEncoding(1252));
            return streamReader.ReadToEnd();
        }
    }
}
5
répondu Magu 2016-02-09 14:50:20

j'ai fait quelque chose de similaire en Python. Fondamentalement, vous avez besoin de beaucoup de données d'échantillon de divers encodages, qui sont décomposés par une fenêtre coulissante de deux octets et stockées dans un dictionnaire (hash), keyed sur byte-paires fournissant des valeurs de listes d'encodages.

étant donné que le dictionnaire (hash), vous prenez votre texte d'entrée et:

  • s'il commence par un caractère BOM ('\xfe\xff 'pour UTF-16-BE, '\xff\xfe' pour UTF-16-LE, '\xef\xbb\xbf ' pour UTF-8 etc), je le traite comme suggéré
  • si ce n'est pas le cas, alors prenez un échantillon suffisamment grand du texte, prenez toutes les paires de octets de l'échantillon et choisissez le codage qui est le moins commun suggéré à partir du dictionnaire.

si vous avez aussi échantillonné des textes encodés en UTF qui ne pas commencent avec n'importe quel BOM, la deuxième étape couvrira ceux qui ont glissé de la première étape.

jusqu'à présent, ça fonctionne pour moi (l'échantillon les données et les données d'entrée subséquentes sont des sous-titres dans diverses langues) avec des taux d'erreur décroissants.

4
répondu tzot 2008-09-18 09:03:38

le constructeur de la classe StreamReader prend un paramètre 'detect encoding'.

3
répondu leppie 2008-09-18 08:04:28

l'outil" uchardet " fonctionne bien en utilisant des modèles de distribution de fréquence de caractères pour chaque jeu de caractères. Les gros fichiers et les fichiers plus" typiques " ont plus de confiance (évidemment).

sur ubuntu, vous venez de apt-get install uchardet .

sur les autres systèmes, obtenir la source, l'utilisation & docs ici: https://github.com/BYVoid/uchardet

3
répondu Erik Aronesty 2013-12-03 14:20:41

si vous pouvez créer un lien vers une bibliothèque C, vous pouvez utiliser libenca . Voir http://cihar.com/software/enca / . De la page de manuel:

Enca lit des fichiers textes donnés, ou des entrées standard quand aucun n'est donné, et utilise la connaissance de leur langue (doit être soutenu par vous) et un mélange d'analyse, d'analyse statistique, de devinettes et de magie noire pour déterminer leurs codages.

C'est GPL v2.

1
répondu Kundor 2013-03-27 03:25:12

a eu le MÊME PROBLÈME MAIS n'a pas encore trouvé une bonne solution pour le détecter automatiquement . Maintenant, la GI utilise PsPad (www.pspad.com) pour cela;) amende de travaux

0
répondu DeeCee 2008-09-18 08:25:40

Puisqu'il s'agit essentiellement de heuristique, il peut aider à utiliser l'encodage des fichiers précédemment reçus de la même source comme un premier indice.

la plupart des gens (ou des applications) font des choses à peu près dans le même ordre à chaque fois, souvent sur la même machine, il est donc très probable que lorsque Bob crée un .csv le fichier et l'envoie à Mary il sera toujours en utilisant Windows-1252 ou quelque soit sa machine par défaut à.

si possible un peu de la formation du client ne fait pas de mal non plus: -)

0
répondu devstuff 2008-12-29 19:42:00

en fait, je cherchais un moyen Générique, Pas de programmation, de détecter l'encodage du fichier, mais je ne l'ai pas encore trouvé. Ce que j'ai trouvé en testant avec différents encodages, c'est que mon texte était UTF-7.

alors où j'ai commencé: StreamReader fichier = Fichier.OpenText (fullfilename);

j'ai dû le changer en: StreamReader fichier = new StreamReader(fullfilename, Système.Texte.Encodage.UTF7);

OpenText suppose que c'est UTF-8.

vous pouvez aussi créer le StreamReader comme ceci nouveau StreamReader (fullfilename, true), le second paramètre signifiant qu'il devrait essayer de détecter l'encodage à partir du byteordermark du fichier, mais cela n'a pas fonctionné dans mon cas.

0
répondu Intraday Tips 2013-07-25 06:59:32

ouvrir le fichier dans AkelPad(ou simplement copier/coller un texte déformé), allez à Edit -> Selection -> Recode... - >cochez "Autodétecter".

0
répondu plavozont 2016-08-22 03:02:43

comme addon à ITmeze post, j'ai utilisé cette fonction pour convertir la sortie de C # port pour Mozilla Universal Charset Detector

    private Encoding GetEncodingFromString(string codePageName)
    {
        try
        {
            return Encoding.GetEncoding(codePageName);
        }
        catch
        {
            return Encoding.ASCII;
        }
    }

MSDN

0
répondu PrivatePyle 2018-03-30 20:54:21

Merci @ Erik Aronesty pour la mention de uchardet .



En attendant, le (le même?) existe pour linux: chardet .

Ou, sur cygwin, vous pouvez utiliser: chardetect .

Voir: chardet page de man: https://www.commandlinux.com/man-page/man1/chardetect.1.html

ce sera heuristique détecter (deviner) le codage des caractères pour chaque fichier et le nom et le niveau de confiance pour chaque fichier est détecté encodage des caractères.

0
répondu Schlacki 2018-05-07 12:26:08

10Y (!) était passé depuis que cela a été demandé, et je ne vois toujours aucune mention de la bonne solution non-GPL DE MS: IMULTILANGUAGE2 API.

la plupart des bibliothèques déjà mentionnées sont basées sur L'UDE de Mozilla - et il semble raisonnable que les navigateurs aient déjà abordé des problèmes similaires. Je ne sais pas ce qu'est la solution de chrome, mais depuis IE 5.0 MS ont libéré le leur, et il est:

  1. sans licence GPL et similaire questions de,
  2. Soutenu et maintenu probablement pour toujours,
  3. Donne riches de sortie - tous les candidats valides pour l'encodage/pages de code avec les scores de confiance,
  4. Étonnamment facile à utiliser (c'est un seul appel de fonction).

C'est un appel COM natif, mais voici quelques très beau travail par Carsten Zeumer, qui gère le mess interop pour l'usage.net. Il y a quelques autres autour, mais en gros, cette bibliothèque ne reçoivent pas l'attention qu'elle mérite.

0
répondu Ofek Shilon 2018-06-04 11:34:33

j'utilise ce code pour détecter Unicode et windows par défaut codepage ansi lors de la lecture d'un fichier. Pour les autres codages, une vérification du contenu est nécessaire, manuellement ou par programmation. Cela peut servir à enregistrer le texte avec le même encodage que quand il a été ouvert. (J'utilise VB.NET)

'Works for Default and unicode (auto detect)
Dim mystreamreader As New StreamReader(LocalFileName, Encoding.Default) 
MyEditTextBox.Text = mystreamreader.ReadToEnd()
Debug.Print(mystreamreader.CurrentEncoding.CodePage) 'Autodetected encoding
mystreamreader.Close()
-2
répondu Thommy Johansson 2015-07-27 18:13:31