Frage

In unserer Anwendung erhalten wir Textdateien (.txt, .csv, etc.) aus verschiedenen Quellen. Beim Lesen, enthalten diese Dateien manchmal Müll, weil die Dateien, in denen in einer anderen / unknown Codepage erstellt.

Gibt es eine Möglichkeit, um (automatisch), um die Codepage einer Textdatei zu erfassen?

Die detectEncodingFromByteOrderMarks, auf dem StreamReader Konstruktor arbeitet für UTF8 und andere Unicode-Dateien markiert, aber ich bin auf der Suche nach einer Möglichkeit, Code-Seiten zu erkennen, wie ibm850, windows1252.


Vielen Dank für Ihre Antworten, das ist, was ich getan habe.

Die Dateien sind wir von Endnutzern erhalten, sie haben keine Ahnung über Codepages haben. Die Empfänger sind auch Endnutzern, jetzt das ist, was sie wissen, über Codepages. Codepages existieren und sind ärgerlich

Lösung:

  • Öffnen Sie die empfangene Datei in Notepad, bei einem verstümmelten Stück Text aussehen. Wenn jemand François oder etwas genannt, mit menschlicher Intelligenz Sie dieses erraten können.
  • Ich habe eine kleine Anwendung erstellt, die der Benutzer die Datei mit öffnen kann, und einen Text eingeben, dass der Benutzer weiß, dass es in der Datei angezeigt wird, wenn die richtige Codepage verwendet wird.
  • Schleife durch alle Codepages, und diejenigen anzuzeigen, die eine Lösung mit dem Benutzer zur Verfügung gestellt Text geben.
  • Wenn mehr als eine Codepage erscheint, bitten Sie den Benutzer mehr Text angeben.
War es hilfreich?

Lösung

Sie können die Codepage nicht erkennen, müssen Sie es sagen. Sie können die Bytes analysieren und denke, es ist, aber das kann einige bizarre (manchmal amüsant) Ergebnisse. Ich kann es jetzt nicht finden, aber ich bin sicher, dass Notepad kann in Anzeigen englischen Text in chinesischen ausgetrickst werden.

Wie auch immer, das ist, was Sie lesen müssen: das absolute Minimum Jeder Software-Entwickler absolut positiv müssen über Unicode und Zeichensätze wissen (keine Ausreden!) .

Im Einzelnen Joel sagt:

  

die wichtigste Tatsache, über Codierungen

     

Wenn Sie alles komplett vergessen, die ich gerade erklärt, erinnern Sie bitte eine äußerst wichtige Tatsache. Es macht keinen Sinn, einen String zu haben, ohne zu wissen, welche Codierung verwendet es. Sie können nicht bleiben länger den Kopf in den Sand und so tun, „plain“ text ASCII ist.   Es ist nicht keine solche Sache wie Nur-Text.

     

Wenn Sie eine Zeichenfolge haben, im Speicher, in einer Datei oder in einer E-Mail, müssen Sie wissen, was kodiert es in ist oder man kann es nicht interpretieren oder sie den Benutzer korrekt angezeigt werden.

Andere Tipps

Wenn Sie suchen nicht-UTF-Codierungen zu erkennen (das heißt keine BOM), sind Sie im Grunde bis auf Heuristiken und statistische Analyse des Textes. Vielleicht haben Sie einen Blick auf die Mozilla Papier auf Universal-charset Erkennung ( gleicher Link, mit bessere Formatierung über Wayback Machine ).

Haben Sie versucht, C # Port für Mozilla Universal-Charset Detector

Beispiel von 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

Dies ist eindeutig falsch. Jeder Web-Browser hat eine Art Universal-charset Detektor mit Seiten zu befassen, die keinerlei Hinweis auf eine Codierung haben. Firefox hat einen. Sie können den Code herunterladen und sehen, wie sie es tut. Sehen Sie eine Dokumentation hier . Im Grunde ist es eine Heuristik, aber eine, die wirklich gut funktioniert.

eine angemessene Menge an Text gegeben, es ist sogar möglich, die Sprache zu erkennen.

Hier ist ein anderes ich nur Google gefunden werden:

Ich weiß, es ist sehr spät für diese Frage, und diese Lösung wird nicht auf einige ansprechen (wegen seiner Englisch-centric Voreingenommenheit und seinen Mangel an statistischen / empirische Tests), aber es ist sehr gut für mich gearbeitet, vor allem für die Verarbeitung hochgeladen CSV-Daten:

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

Vorteile:

  • BOM Erkennung Einbau-
  • Standard / Rückfall codiert, anpassbare
  • recht zuverlässig (in meiner Erfahrung) für westeuropäische basierte Dateien einig exotischen Daten (zB französisch-Namen) mit einer Mischung aus UTF-8 und Latin-1-Stil-Dateien enthalten - im Grunde den Großteil der USA und Westeuropa Umgebungen .

Hinweis: Ich bin derjenige, der diese Klasse geschrieben, so offensichtlich mit einem Körnchen Salz nehmen Sie es! :)

Notepad ++ hat diese Funktion out-of-the-box. Es unterstützt auch sie zu verändern.

Sie suchen andere Lösung, fand ich, dass

https://code.google.com/p/ude/

Diese Lösung ist ein bisschen schwer.

Ich brauchte einige grundlegende Codierungserkennung, basierend auf 4 Bytes ersten und wahrscheinlich xml charset-Erkennung - so habe ich nahm einig Beispiel-Quellcode aus dem Internet und hinzugefügt leicht modifizierte Version von

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 wahrscheinlich erstes 1024 Bytes aus der Datei zu lesen, aber ich lade ganze Datei.

Wenn jemand für eine 93,9% ige Lösung suchen. Dies 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 getan. Grundsätzlich müssen Sie eine Menge Abtastdaten von verschiedenen Codierungen, die durch ein gleitendes Zwei-Byte-Fenster gebrochen sind nach unten und in einem Wörterbuch (hash) gespeichert ist, verkeilten auf Byte-Paare Werten von Listen von Kodierungen bereitgestellt wird.

Da Wörterbuch (hash), können Sie Ihre Eingabe von Text nehmen und:

  • , wenn es mit jedem BOM Zeichen beginnt ( '\ xfe \ xff' für UTF-16-BE, '\ xff \ xfe' für UTF-16-LE, '\ XeF \ xbb \ xbf' für UTF-8 usw. ), ich behandle sie wie vorgeschlagen
  • wenn nicht, dann eine ausreichend große Probe des Textes haben, nehmen alle Byte-Paare der Probe und wählen Sie die Codierung, die das kleinste gemeinsame aus dem Wörterbuch vorgeschlagen ist.

Wenn Sie habe auch UTF codierte Texte abgetastet, dass nicht beginnen mit jeder BOM, der zweite Schritt werden diejenigen umfassen, die aus dem ersten Schritt gerutscht.

Bisher funktioniert es für mich (die Beispieldaten und nachfolgende Eingangsdaten Untertitel in verschiedenen Sprachen) mit Fehlerraten zu verringern.

Die Konstruktor der Klasse Stream nimmt einen ‚erkennen Codierung‘ Parameter.

Das Werkzeug „uchardet“ tut dies auch unter Verwendung von Zeichenhäufigkeitsverteilung Modelle für jeden charset. Größere Dateien und mehr „typische“ Dateien mehr Vertrauen haben (offensichtlich).

Auf ubuntu, die Sie gerade apt-get install uchardet.

Auf anderen Systemen erhalten die Quelle, Verwendung & docs hier: https://github.com/BYVoid/uchardet

Wenn Sie eine C-Bibliothek verknüpfen können, können Sie libenca verwenden. Siehe http://cihar.com/software/enca/ . Aus der Manpage:

  

Enca liest gegebene Textdateien oder Standardeingabe, wenn keine angegeben sind,   und nutzt das Wissen über ihre Sprache (muss von Ihnen unterstützt werden) und   eine Mischung aus Analyse, statistischer Analysen, erraten und schwarzer Magie   ihre Kodierungen zu bestimmen.

Es ist GPL v2.

Haben Sie das gleiche Problem, aber nicht eine gute Lösung noch zur Erfassung automatisch gefunden. Jetzt, dass die Verwendung PsPad (www.pspad.com) im;) Adaequat

Da im Grunde kommt es auf Heuristiken, kann es helfen, die Codierung von zuvor empfangenen Dateien aus der gleichen Quelle wie ein ersten Hinweis zu verwenden.

Die meisten Menschen (oder Anwendungen) zu tun Sachen in so ziemlich der gleichen Reihenfolge oft jedes Mal, auf der gleichen Maschine, so dass ihr sehr wahrscheinlich, dass, wenn Bob erstellt eine CSV-Datei und sendet sie an Mary, es wird immer Windows verwenden -1252 oder was auch immer seine Maschine standardmäßig.

Wenn möglich ein bisschen Kundentraining schadet nie - entweder)

suchte ich eigentlich für eine generische, nicht Programmierung Möglichkeit, die Datei-Codierung des Erfassens, aber ich fand nicht, dass noch. Was ich fand, indem sie mit verschiedenen Kodierungen Prüfung war, dass mein Text war UTF-7.

Also, wo ich zum ersten Mal tat: Stream file = File.OpenText (fullfilename);

Ich musste es ändern: Stream file = new Stream (fullfilename, System.Text.Encoding.UTF7);

Open Text übernimmt es ist UTF-8.

Sie können auch die Stream wie folgt erstellen new Stream (fullfilename, true), der zweite Parameter was bedeutet, dass es sollte die Codierung von der byteordermark der Datei versuchen und erkennen, aber das nicht in meinem Fall nicht funktionierte.

Öffnen Sie die Datei in AkelPad (oder kopieren / nur einen verstümmelten Text einfügen), bearbeiten gehen -> Auswahl -> Recode ... -.> Auf "Autodetect"

Als Addon Beitrag ITmeze, habe ich diese Funktion verwendet, um die Ausgabe von C # Port für Mozilla Universal-Charset Detector zu konvertieren

    private Encoding GetEncodingFromString(string codePageName)
    {
        try
        {
            return Encoding.GetEncoding(codePageName);
        }
        catch
        {
            return Encoding.ASCII;
        }
    }

MSDN

Danke @ Erik Aronesty für die Erwähnung uchardet .
Inzwischen ist die (? Selbe) Tool gibt es für Linux:. chardet
Oder auf Cygwin können Sie verwenden möchten. chardetect

Siehe auch: chardet Manpage: https://www.commandlinux.com/man-page/man1/chardetect.1 .html

Dies wird heuristisch erkennen (erraten) die Zeichenkodierung für jede Datei gegeben und wird den Namen und Konfidenzniveau für jede Datei erkannt Zeichencodierung melden.

(!)

10Y war vergangen, seit dieser gefragt wurde, und ich sehe noch nicht die Rede von MS ist gut, nicht-GPL'ed Lösung: IMultiLanguage2 API.

Die meisten Bibliotheken bereits auf Mozillas UDE erwähnt basiert - und es scheint sinnvoll, dass Browser bereits ähnliche Probleme in Angriff genommen hat. Ich weiß nicht, was Chrom-Lösung ist, aber da IE 5.0 MS ihre freigegeben haben, und es ist:

  1. Frei von GPL-and-the-ähnlichen Lizenzierungsfragen,
  2. Unterstützt und gepflegt wahrscheinlich für immer,
  3. Gibt fette Ausgabe - alle gültigen Kandidaten für die Codierung / Codepages zusammen mit Konfidenzgrade,
  4. überraschend einfach zu bedienen (es ist ein einziger Funktionsaufruf).

Es ist ein native COM-Aufruf, aber hier einige sehr schöne Arbeit von Carsten Zeumer, dass die Interop-Chaos für .net Nutzung behandelt. Es gibt einige andere um, aber im Großen und Ganzen diese Bibliothek bekommen nicht die Aufmerksamkeit, die es verdient.

Ich benutze diesen Code Unicode und Windows-Standard ANSI-Codepage zu erkennen, wenn eine Datei zu lesen. Für andere Codierungen eine Überprüfung des Inhalts notwendig ist, manuell oder durch Programmierung. Dies kann dazu verwendet de thé Text mit der gleichen Codierung zu speichern, wenn es geöffnet wurde. (Ich verwende 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()
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top