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.
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.
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 ).
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.");
}
}
}
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:
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! :)
à 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.
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();
}
}
}
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.
le constructeur de la classe StreamReader prend un paramètre 'detect encoding'.
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
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.
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
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: -)
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.
ouvrir le fichier dans AkelPad(ou simplement copier/coller un texte déformé), allez à Edit -> Selection -> Recode... - >cochez "Autodétecter".
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;
}
}
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.
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:
- sans licence GPL et similaire questions de,
- Soutenu et maintenu probablement pour toujours,
- Donne riches de sortie - tous les candidats valides pour l'encodage/pages de code avec les scores de confiance,
- É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.
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()