web-dev-qa-db-fra.com

Comment détecter le codage de caractères d'un fichier texte?

J'essaie de détecter quel encodage de caractères est utilisé dans mon fichier.

J'essaie avec ce code pour obtenir le codage standard

public static Encoding GetFileEncoding(string srcFile)
    {
      // *** Use Default of Encoding.Default (Ansi CodePage)
      Encoding enc = Encoding.Default;

      // *** Detect byte order mark if any - otherwise assume default
      byte[] buffer = new byte[5];
      FileStream file = new FileStream(srcFile, FileMode.Open);
      file.Read(buffer, 0, 5);
      file.Close();

      if (buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf)
        enc = Encoding.UTF8;
      else if (buffer[0] == 0xfe && buffer[1] == 0xff)
        enc = Encoding.Unicode;
      else if (buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 0xfe && buffer[3] == 0xff)
        enc = Encoding.UTF32;
      else if (buffer[0] == 0x2b && buffer[1] == 0x2f && buffer[2] == 0x76)
        enc = Encoding.UTF7;
      else if (buffer[0] == 0xFE && buffer[1] == 0xFF)      
        // 1201 unicodeFFFE Unicode (Big-Endian)
        enc = Encoding.GetEncoding(1201);      
      else if (buffer[0] == 0xFF && buffer[1] == 0xFE)      
        // 1200 utf-16 Unicode
        enc = Encoding.GetEncoding(1200);


      return enc;
    }

Mes cinq premiers octets sont 60, 118, 56, 46 et 49.

Existe-t-il un graphique indiquant quel codage correspond à ces cinq premiers octets?

72
Cédric Boivin

Vous ne pouvez pas compter sur le fichier ayant une nomenclature. UTF-8 n'en a pas besoin. Et les encodages non-Unicode n'ont même pas de nomenclature. Il existe cependant d'autres moyens de détecter le codage.

UTF-32

La nomenclature est 00 FEC (pour BE) ou FF FE 00, 00 (pour LE).

Mais UTF-32 est facile à détecter, même sans nomenclature. En effet, la plage de points de code Unicode est limitée à U + 10FFFF et les unités UTF-32 ont donc toujours le modèle 00 {00-10} xx xx (pour BE) ou xx xx {00-10} 00 (pour LE). . Si les données ont une longueur multiple de 4 et suivent l'un de ces modèles, vous pouvez sans risque supposer qu'il s'agit du format UTF-32. Les faux positifs sont presque impossibles en raison de la rareté de 00 octets dans les codages orientés octets.

US-ASCII

Pas de nomenclature, mais vous n'en avez pas besoin. ASCII peut être facilement identifié par le manque d'octets dans la plage de 80-FF.

UTF-8

La nomenclature correspond à EF BB BF. Mais vous ne pouvez pas compter sur cela. De nombreux fichiers UTF-8 ne possèdent pas de nomenclature, en particulier s'ils proviennent de systèmes autres que Windows.

Mais vous pouvez sans risque supposer que, si un fichier est validé en tant que UTF-8, il est UTF-8. Les faux positifs sont rares.

Plus précisément, étant donné que les données ne sont pas ASCII, le taux de faux positifs pour une séquence de 2 octets n'est que de 3,9% (1920/49152). Pour une séquence de 7 octets, c'est moins de 1%. Pour une séquence de 12 octets, c'est moins de 0,1%. Pour une séquence de 24 octets, c'est moins de 1 sur un million.

UTF-16

La nomenclature est FE FF (pour BE) ou FF FE (pour LE). Notez que la nomenclature UTF-16LE se trouve au début de la nomenclature UTF-32LE. Vérifiez donc d'abord UTF-32.

Si vous avez un fichier composé principalement de caractères ISO-8859-1, le fait que la moitié de ses octets soient égale à 00 sera également un indicateur fort de la norme UTF-16.

Sinon, le seul moyen fiable de reconnaître UTF-16 sans nomenclature est de rechercher des paires de substitution (D [8-B] xx D [CF] xx), mais les caractères non-BMP sont trop rarement utilisés pour rendre cette approche pratique. .

XML

Si votre fichier commence par les octets 3C 3F 78 6D 6C (c’est-à-dire les caractères ASCII "" <? Xml "), recherchez une déclaration encoding=. Si présent, utilisez cet encodage. S'il est absent, supposons UTF-8, qui est le codage XML par défaut.

Si vous devez prendre en charge EBCDIC, recherchez également la séquence équivalente 4C 6F A7 94 93.

En général, si vous avez un format de fichier contenant une déclaration de codage, recherchez cette déclaration plutôt que d'essayer de deviner le codage.

Aucune de ces réponses

Il existe des centaines d'autres encodages, qui nécessitent davantage d'efforts de détection. Je recommande d'essayer détecteur de charset de Mozilla ou n portage .NET .

Un défaut raisonnable

Si vous avez exclu les codages UTF et que vous n'avez pas de déclaration de codage ou de détection statistique pointant vers un codage différent, supposons que ISO-8859-1 ou le proche parent Windows -1252 . (Notez que la dernière norme HTML requiert une déclaration "ISO-8859-1" pour être interprétée comme Windows-1252.) Page de code par défaut de Windows pour l'anglais (et d'autres langues populaires telles que l'espagnol, le portugais, l'allemand et le français), il s'agit du codage le plus couramment rencontré, à l'exception de l'UTF-8.

79
dan04

Si vous souhaitez rechercher une solution "simple", vous trouverez peut-être utile ce cours:

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

La détection de nomenclature est automatiquement effectuée en premier, puis tente de différencier les codages Unicode sans nomenclature par rapport à un autre codage par défaut (généralement Windows-1252, incorrectement étiqueté Encoding.ASCII dans .Net).

Comme indiqué ci-dessus, une solution "plus lourde" impliquant NCharDet ou MLang peut être plus appropriée, et comme je l'indique sur la page de présentation de cette classe, le mieux est de fournir une forme ou une autre d'interactivité avec l'utilisateur, car Il n'y a pas de taux de détection de 100% possible!

9
Tao

Utilisez StreamReader et dirigez-le pour détecter le codage pour vous:

using (var reader = new System.IO.StreamReader(path, true))
{
    var currentEncoding = reader.CurrentEncoding;
}

Et utilisez les identificateurs de page de code https://msdn.Microsoft.com/en-us/library/windows/desktop/dd317756 (v = vs.85) .aspx afin de changer de logique en fonction de celle-ci.

5
Phil Hunt

Plusieurs réponses sont ici mais personne n’a posté de code utile.

Voici mon code qui détecte tous les encodages que Microsoft détecte dans Framework 4 dans la classe StreamReader.

Vous devez évidemment appeler cette fonction immédiatement après l'ouverture du flux avant de lire quoi que ce soit d'autre dans le flux, car les nomenclatures sont les premiers octets du flux.

Cette fonction nécessite un flux pouvant rechercher (par exemple un FileStream). Si vous avez un flux qui ne peut pas chercher, vous devez écrire un code plus compliqué renvoyant un tampon d'octets avec les octets déjà lus mais qui ne sont pas des nomenclatures.

/// <summary>
/// UTF8    : EF BB BF
/// UTF16 BE: FE FF
/// UTF16 LE: FF FE
/// UTF32 BE: 00 00 FE FF
/// UTF32 LE: FF FE 00 00
/// </summary>
public static Encoding DetectEncoding(Stream i_Stream)
{
    if (!i_Stream.CanSeek || !i_Stream.CanRead)
        throw new Exception("DetectEncoding() requires a seekable and readable Stream");

    // Try to read 4 bytes. If the stream is shorter, less bytes will be read.
    Byte[] u8_Buf = new Byte[4];
    int s32_Count = i_Stream.Read(u8_Buf, 0, 4);
    if (s32_Count >= 2)
    {
        if (u8_Buf[0] == 0xFE && u8_Buf[1] == 0xFF)
        {
            i_Stream.Position = 2;
            return new UnicodeEncoding(true, true);
        }

        if (u8_Buf[0] == 0xFF && u8_Buf[1] == 0xFE)
        {
            if (s32_Count >= 4 && u8_Buf[2] == 0 && u8_Buf[3] == 0)
            {
                i_Stream.Position = 4;
                return new UTF32Encoding(false, true);
            }
            else
            {
                i_Stream.Position = 2;
                return new UnicodeEncoding(false, true);
            }
        }

        if (s32_Count >= 3 && u8_Buf[0] == 0xEF && u8_Buf[1] == 0xBB && u8_Buf[2] == 0xBF)
        {
            i_Stream.Position = 3;
            return Encoding.UTF8;
        }

        if (s32_Count >= 4 && u8_Buf[0] == 0 && u8_Buf[1] == 0 && u8_Buf[2] == 0xFE && u8_Buf[3] == 0xFF)
        {
            i_Stream.Position = 4;
            return new UTF32Encoding(true, true);
        }
    }

    i_Stream.Position = 0;
    return Encoding.Default;
}
4
Elmue
2
Jon
2
Steven K.

J'utilise de c'est un port C # de Mozilla Universal Charset Detector. Il est facile à utiliser et donne de très bons résultats.

1
Julien Jacobs

Si votre fichier commence par les octets 60, 118, 56, 46 et 49, vous avez un cas ambigu. Il peut s'agir de UTF-8 (sans nomenclature) ou de l'un des codages à un octet tels qu'ASCII, ANSI, ISO-8859-1, etc.

1
Codo