In unserer Anwendung erhalten wir Textdateien (.txt
, .csv
usw.) aus verschiedenen Quellen. Beim Lesen enthalten diese Dateien manchmal Müll, da die Dateien in einer anderen/unbekannten Codepage erstellt wurden.
Gibt es eine Möglichkeit, die Codepage einer Textdatei (automatisch) zu erkennen?
Die Variable detectEncodingFromByteOrderMarks
im Konstruktor StreamReader
funktioniert für UTF8
und andere mit Unicode markierte Dateien. Ich suche jedoch nach einer Möglichkeit, Codeseiten wie ibm850
, windows1252
zu erkennen.
Danke für Ihre Antworten, das habe ich getan.
Die Dateien, die wir erhalten, stammen von Endbenutzern, sie haben keine Ahnung von Codepages. Die Empfänger sind auch Endbenutzer, das wissen sie inzwischen über Codepages: Codepages existieren und sind ärgerlich.
Lösung:
Sie können die Codepage nicht erkennen, es muss Ihnen mitgeteilt werden. Sie können die Bytes analysieren und erraten, aber das kann zu bizarren (manchmal amüsanten) Ergebnissen führen. Ich kann es jetzt nicht finden, aber ich bin mir sicher, dass Notepad dazu gebracht werden kann, englischen Text auf Chinesisch anzuzeigen.
Jedenfalls müssen Sie Folgendes lesen: Das absolute Minimum, das jeder Softwareentwickler absolut und positiv über Unicode und Zeichensätze (keine Ausreden!) Wissen muss .
Speziell sagt Joel:
Die wichtigste Information über Kodierungen
Wenn Sie alles, was ich gerade erklärt habe, vollständig vergessen haben, denken Sie bitte an eine äußerst wichtige Tatsache. Es ist nicht sinnvoll, eine Zeichenfolge zu haben, ohne zu wissen, welche Kodierung verwendet wird. Sie können Ihren Kopf nicht mehr in den Sand stecken und so tun, als sei "einfacher" Text ASCII . Es gibt keinen einfachen Text.
Wenn Sie eine Zeichenfolge, im Speicher, in einer Datei oder in einer E-Mail-Nachricht haben, müssen Sie wissen, in welcher Kodierung sich diese befindet, oder Sie können sie nicht richtig interpretieren oder den Benutzern nicht richtig anzeigen.
Wenn Sie nach Nicht-UTF-Kodierungen suchen möchten (d. H. Keine Stückliste), sind im Grunde nur Heuristiken und statistische Analysen des Textes erforderlich. Vielleicht möchten Sie einen Blick auf das Mozilla-Papier zur universellen Zeichensatzerkennung ( gleicher Link mit besserer Formatierung über Wayback Machine ) werfen.
Haben Sie versucht, C # -Port für Mozilla Universal Charset Detector
Beispiel aus 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.");
}
}
}
Sie können die Codepage nicht erkennen
Das ist eindeutig falsch. Jeder Webbrowser verfügt über einen universellen Zeichensatz-Detektor für Seiten, die keinerlei Hinweise auf eine Kodierung enthalten. Firefox hat einen. Sie können den Code herunterladen und sehen, wie er funktioniert. Siehe Dokumentation hier . Im Grunde ist es eine Heuristik, die aber sehr gut funktioniert.
Bei einer angemessenen Textmenge ist es sogar möglich, die Sprache zu erkennen.
Hier ist noch einer Ich habe gerade mit Google gefunden:
Ich weiß, dass es für diese Frage sehr spät ist, und diese Lösung wird einige nicht ansprechen (aufgrund ihrer englisch-zentrischen Neigung und des Fehlens statistischer/empirischer Tests), aber es hat für mich sehr gut funktioniert, insbesondere für die Verarbeitung hochgeladener CSV-Daten:
http://www.architectshack.com/TextFileEncodingDetector.ashx
Vorteile:
Anmerkung: Ich bin derjenige, der diese Klasse geschrieben hat, also nimm es offensichtlich mit einem Salzkorn! :)
Auf der Suche nach einer anderen Lösung habe ich das gefunden
https://code.google.com/p/ude/
diese Lösung ist ziemlich schwer.
Ich brauchte eine grundlegende Codierungserkennung, basierend auf 4 ersten Bytes und wahrscheinlich der Erkennung von XML-Zeichensätzen. Daher habe ich Quellcode aus dem Internet genommen und eine leicht modifizierte Version von hinzugefügt
http://lists.w3.org/Archives/Public/www-validator/2002Aug/0084.html
geschrieben für 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
}
Es reicht aus, um wahrscheinlich zuerst 1024 Bytes aus der Datei zu lesen, aber ich lade die ganze Datei.
Notepad ++ Diese Funktion ist standardmäßig verfügbar. Es unterstützt auch das Ändern.
Wenn jemand nach einer 93,9% igen Lösung sucht. Das funktioniert für mich:
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();
}
}
}
Ich habe etwas Ähnliches in Python gemacht. Grundsätzlich benötigen Sie viele Beispieldaten aus verschiedenen Kodierungen, die durch ein gleitendes Zwei-Byte-Fenster zerlegt und in einem Wörterbuch (Hash) gespeichert werden, wobei die Byte-Paare die Werte der Kodierlisten enthalten.
In Anbetracht dieses Wörterbuchs (Hash) nehmen Sie Ihren Eingabetext und:
Wenn Sie auch UTF-codierte Texte abgetastet haben, die nicht mit einer Stückliste beginnen, werden im zweiten Schritt diejenigen behandelt, die vom ersten Schritt abgerutscht sind.
Bisher funktioniert es für mich (die Beispieldaten und die nachfolgenden Eingabedaten sind Untertitel in verschiedenen Sprachen) mit abnehmenden Fehlerraten.
Das Tool "uchardet" macht dies gut, indem es Zeichenhäufigkeitsverteilungsmodelle für jeden Zeichensatz verwendet. Größere Dateien und "typischere" Dateien haben mehr Vertrauen (offensichtlich).
Auf Ubuntu apt-get install uchardet
.
Auf anderen Systemen erhalten Sie Quelle, Verwendung und Dokumente hier: https://github.com/BYVoid/uchardet
Der Konstruktor der StreamReader-Klasse verwendet einen Parameter zum Erkennen der Codierung.
Wenn Sie eine Verknüpfung zu einer C-Bibliothek herstellen können, können Sie libenca
verwenden. Siehe http://cihar.com/software/enca/ . Aus der Manpage:
Enca liest gegebene Textdateien oder Standardeingaben, wenn keine angegeben sind und verwendet Kenntnisse über ihre Sprache (muss von Ihnen unterstützt werden) und eine Mischung aus Analyse, statistischer Analyse, Erraten und schwarzer Magie um ihre Kodierungen zu bestimmen.
Es ist GPL v2.
Habe das gleiche Problem, aber noch keine gute Lösung gefunden, um es automatisch zu erkennen. Jetzt benutze ich PsPad (www.pspad.com) dafür;) Funktioniert gut
Danke @ Erik Aronesty für die Erwähnung von uchardet
.
Mittlerweile existiert das (gleiche?) Werkzeug für linux: chardet
.
Oder möchten Sie auf cygwin Folgendes verwenden: chardetect
.
Siehe: chardet-Manpage:https://www.commandlinux.com/man-page/man1/chardetect.1.html
Dadurch wird die Zeichencodierung für jede Datei heuristisch ermittelt (erraten) und der Name und das Vertrauensniveau für die erkannte Zeichencodierung jeder Datei angegeben.
Ich habe eigentlich nach einer generischen, nicht programmierbaren Methode gesucht, um die Dateicodierung zu erkennen, aber ich habe das noch nicht gefunden ... Was ich beim Testen mit verschiedenen Kodierungen fand, war, dass mein Text UTF-7 war.
Wo ich das zuerst gemacht habe: StreamReader file = File.OpenText (fullfilename);
Ich musste es ändern in: StreamReader Datei = neuer StreamReader (vollständiger Dateiname, System.Text.Encoding.UTF7);
OpenText geht von UTF-8 aus.
sie können den StreamReader auch wie folgt erstellen: __.new StreamReader (fullfilename, true); der zweite Parameter bedeutet, dass er versuchen sollte, die Kodierung anhand des Byte-Markers der Datei zu ermitteln, aber das hat in meinem Fall nicht funktioniert.
Als Addon zu ITmeze post habe ich diese Funktion verwendet, um die Ausgabe des C # -Ports für den Mozilla Universal Charset Detector zu konvertieren
private Encoding GetEncodingFromString(string codePageName)
{
try
{
return Encoding.GetEncoding(codePageName);
}
catch
{
return Encoding.ASCII;
}
}
Öffnen Sie die Datei in AkelPad (oder kopieren oder fügen Sie einfach einen verstümmelten Text ein), gehen Sie zu Bearbeiten -> Auswahl -> Neu kodieren ... -> und aktivieren Sie die Option "Automatische Erkennung".
Da es im Wesentlichen auf Heuristiken ankommt, kann es hilfreich sein, die Codierung zuvor empfangener Dateien aus derselben Quelle als ersten Hinweis zu verwenden.
Die meisten Leute (oder Anwendungen) erledigen jedes Mal Dinge in der gleichen Reihenfolge, oft auf demselben Rechner. Wenn Bob also eine CSV-Datei erstellt und an Mary sendet, wird er immer Windows-1252 verwenden was auch immer seine Maschine standardmäßig vorsieht.
Nach Möglichkeit schmerzt auch ein bisschen Kundenschulung nicht :-)
10Y (!) War vergangen, seitdem gefragt wurde, und trotzdem sehe ich keine Erwähnung von MSs guter, nicht GPL-Lösung: IMultiLanguage2 API.
Die meisten bereits erwähnten Bibliotheken basieren auf Mozillas UDE - und es scheint vernünftig, dass Browser ähnliche Probleme bereits gelöst haben. Ich weiß nicht, was die Lösung von Chrome ist, aber seit IE 5.0 haben MS ihre freigegeben, und es ist:
Es ist ein nativer COM-Aufruf, aber hier sind einige sehr schöne Arbeiten von Carsten Zeumer, die das Interop-Chaos für die .net-Verwendung handhaben. Es gibt einige andere, aber im Großen und Ganzen bekommt diese Bibliothek nicht die Aufmerksamkeit, die sie verdient.