web-dev-qa-db-de.com

Wie kann ich die Codierung/Codepage einer Textdatei erkennen?

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:  

  • Öffnen Sie die empfangene Datei in Notepad, und sehen Sie sich einen verstümmelten Text an. Wenn jemand François oder so genannt wird, können Sie dies mit Ihrer menschlichen Intelligenz erraten.
  • Ich habe eine kleine App erstellt, mit der der Benutzer die Datei öffnen kann, und einen Text eingeben, von dem der Benutzer weiß, dass er in der Datei angezeigt wird, wenn die richtige Codepage verwendet wird. 
  • Durchlaufen Sie alle Codepages und zeigen Sie diejenigen an, die eine Lösung mit dem vom Benutzer angegebenen Text enthalten. 
  • Wenn mehr als eine Codepage erscheint, bitten Sie den Benutzer, mehr Text anzugeben.
283
GvS

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.

255
JV.

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.

30
Tomer Gabel

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.");
        }
    }
}    
21
ITmeze

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:

15
shoosh

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:

  • Stücklistenerkennung eingebaut
  • Standard/Fallback-Codierung anpassbar
  • ziemlich zuverlässig (meiner Erfahrung nach) für Dateien in Westeuropa, die einige exotische Daten enthalten (z. B. französische Namen) mit einer Mischung aus UTF-8- und Latin-1-Dateien - im Wesentlichen der Großteil der US- und Westeuropäischen Umgebungen.

Anmerkung: Ich bin derjenige, der diese Klasse geschrieben hat, also nimm es offensichtlich mit einem Salzkorn! :)

8
Tao

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.

7
TarmoPikaro

Notepad ++ Diese Funktion ist standardmäßig verfügbar. Es unterstützt auch das Ändern.

7
hegearon

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();
        }
    }
}
5
Magu

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 es mit einem Stücklistenzeichen beginnt ('\ xfe\xff' für UTF-16-BE, '\ xff\xfe' für UTF-16-LE, '\ xef\xbb\xbf' für UTF-8 usw.), I Behandle es wie vorgeschlagen
  • wenn nicht, nehmen Sie eine ausreichend große Probe des Textes, nehmen Sie alle Byte-Paare der Probe und wählen Sie die Kodierung aus, die am wenigsten häufig aus dem Wörterbuch vorgeschlagen wird.

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.

4
tzot

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

3
Erik Aronesty

Der Konstruktor der StreamReader-Klasse verwendet einen Parameter zum Erkennen der Codierung.

3
leppie

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.

1
Kundor

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

0
DeeCee

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.

0
Schlacki

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.

0
Intraday Tips

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;
        }
    }

MSDN

0
PrivatePyle

Ö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".

0
plavozont

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 :-)

0
devstuff

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:

  1. Frei von GPL-ähnlichen Lizenzproblemen,
  2. Gesichert und wahrscheinlich für immer gewartet,
  3. Liefert eine reichhaltige Ausgabe - alle gültigen Kandidaten für die Codierung/Codepages zusammen mit Vertrauenswerten
  4. Überraschend einfach zu bedienen (es handelt sich um einen einzelnen Funktionsaufruf).

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.

0
Ofek Shilon