Moyen efficace de trouver le codage d’un fichier

Oui, c’est une question très fréquente, et cette question est vague pour moi et puisque je n’en sais pas beaucoup.

Mais je voudrais un moyen très précis de trouver un encodage de fichiers. Tellement précis que Notepad ++ est.

La propriété StreamReader.CurrentEncoding renvoie rarement le codage de fichier texte correct pour moi. J’ai eu plus de succès pour déterminer le caractère d’un fichier en analysant sa marque d’ordre d’octet (BOM):

 ///  /// Determines a text file's encoding by analyzing its byte order mark (BOM). /// Defaults to ASCII when detection of the text file's endianness fails. ///  /// The text file to analyze. /// The detected encoding. public static Encoding GetEncoding(ssortingng filename) { // Read the BOM var bom = new byte[4]; using (var file = new FileStream(filename, FileMode.Open, FileAccess.Read)) { file.Read(bom, 0, 4); } // Analyze the BOM if (bom[0] == 0x2b && bom[1] == 0x2f && bom[2] == 0x76) return Encoding.UTF7; if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf) return Encoding.UTF8; if (bom[0] == 0xff && bom[1] == 0xfe) return Encoding.Unicode; //UTF-16LE if (bom[0] == 0xfe && bom[1] == 0xff) return Encoding.BigEndianUnicode; //UTF-16BE if (bom[0] == 0 && bom[1] == 0 && bom[2] == 0xfe && bom[3] == 0xff) return Encoding.UTF32; return Encoding.ASCII; } 

En revanche, vous pouvez modifier la dernière ligne de cette méthode pour renvoyer Encoding.Default afin que le codage de la page de codes ANSI actuelle du système d’exploitation soit renvoyé par défaut.

Le code suivant fonctionne bien pour moi, en utilisant la classe StreamReader :

  using (var reader = new StreamReader(fileName, defaultEncodingIfNoBom, true)) { reader.Peek(); // you need this! var encoding = reader.CurrentEncoding; } 

L’astuce consiste à utiliser l’appel Peek , sinon, .NET n’a rien fait (et il n’a pas lu le préambule, la nomenclature). Bien sûr, si vous utilisez un autre appel ReadXXX avant de vérifier le codage, cela fonctionne aussi.

Si le fichier ne contient aucune nomenclature, le codage defaultEncodingIfNoBom sera utilisé. Il existe également un StreamReader sans cette méthode de surcharge (dans ce cas, l’encodage par défaut (ANSI) sera utilisé par défautEncodingIfNoBom), mais je recommande de définir ce que vous considérez comme l’encodage par défaut dans votre contexte.

Je l’ai testé avec succès avec des fichiers avec nomenclature pour UTF8, UTF16 / Unicode (LE & BE) et UTF32 (LE & BE). Cela ne fonctionne pas pour UTF7.

J’essaierais les étapes suivantes:

1) Vérifier s’il y a une marque d’ordre des octets

2) Vérifier si le fichier est valide UTF8

3) Utilisez la page de codes locale “ANSI” (ANSI comme Microsoft le définit)

L’étape 2 fonctionne car la plupart des séquences non ASCII dans les pages de code autres que UTF8 ne sont pas valides UTF8.

Vérifie ça.

UDE

Ceci est un portage de Mozilla Universal Charset Detector et vous pouvez l’utiliser comme ça …

 public static void Main(Ssortingng[] args) { ssortingng 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."); } } } 

Regardez ici pour c #

https://msdn.microsoft.com/en-us/library/system.io.streamreader.currentencoding%28v=vs.110%29.aspx

 ssortingng path = @"path\to\your\file.ext"; using (StreamReader sr = new StreamReader(path, true)) { while (sr.Peek() >= 0) { Console.Write((char)sr.Read()); } //Test for the encoding after reading, or at least //after the first read. Console.WriteLine("The encoding used was {0}.", sr.CurrentEncoding); Console.ReadLine(); Console.WriteLine(); } 

Les codes suivants sont mes codes Powershell pour déterminer si certains fichiers cpp ou h ou ml sont encodés avec ISO-8859-1 (Latin-1) ou UTF-8 sans BOM, si ni l’un ni l’autre ne supposent qu’il s’agisse de GB18030. Je suis un Chinois travaillant en France et MSVC enregistre sous Latin-1 sur ordinateur français et enregistre en tant que GB sur un ordinateur chinois. Cela m’aide à éviter les problèmes de codage lors des échanges de fichiers sources entre mon système et mes collègues.

Le chemin est simple, si tous les caractères sont compris entre x00-x7E, ASCII, UTF-8 et Latin-1 sont les mêmes, mais si je lis un fichier non-ASCII avec UTF-8, nous trouverons le caractère spécial , alors essayez de lire avec Latin-1. En latin-1, entre \ x7F et \ xAF est vide, alors que GB utilise plein entre x00-xFF, donc si j’en ai entre les deux, ce n’est pas du latin-1

Le code est écrit dans PowerShell, mais utilise .net, il est donc facile d’être traduit en C # ou F #

 $Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False) foreach($i in Get-ChildItem .\ -Recurse -include *.cpp,*.h, *.ml) { $openUTF = New-Object System.IO.StreamReader -ArgumentList ($i, [Text.Encoding]::UTF8) $contentUTF = $openUTF.ReadToEnd() [regex]$regex = ' ' $c=$regex.Matches($contentUTF).count $openUTF.Close() if ($c -ne 0) { $openLatin1 = New-Object System.IO.StreamReader -ArgumentList ($i, [Text.Encoding]::GetEncoding('ISO-8859-1')) $contentLatin1 = $openLatin1.ReadToEnd() $openLatin1.Close() [regex]$regex = '[\x7F-\xAF]' $c=$regex.Matches($contentLatin1).count if ($c -eq 0) { [System.IO.File]::WriteAllLines($i, $contentLatin1, $Utf8NoBomEncoding) $i.FullName } else { $openGB = New-Object System.IO.StreamReader -ArgumentList ($i, [Text.Encoding]::GetEncoding('GB18030')) $contentGB = $openGB.ReadToEnd() $openGB.Close() [System.IO.File]::WriteAllLines($i, $contentGB, $Utf8NoBomEncoding) $i.FullName } } } Write-Host -NoNewLine 'Press any key to continue...'; $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');