Bei der Arbeit scheint es, als würde keine Woche ohne eine kodierungsbedingte Verbindung, ein Unglück oder eine Katastrophe vergehen. Das Problem ist normalerweise auf Programmierer zurückzuführen, die glauben, eine Textdatei zuverlässig verarbeiten zu können, ohne die Codierung anzugeben. Aber du kannst nicht.
Daher wurde beschlossen, Dateien künftig zu verbieten, jemals Namen zu haben, die mit *.txt
oder enden *.text
. Der Gedanke ist, dass diese Erweiterungen den Gelegenheitsprogrammierer in eine langweilige Selbstzufriedenheit in Bezug auf Codierungen führen, was zu einer unsachgemäßen Handhabung führt. Es wäre fast besser, überhaupt keine Erweiterung zu haben, denn zumindest dann wissen Sie , dass Sie nicht wissen, was Sie haben.
Wir werden jedoch nicht so weit gehen. Stattdessen wird erwartet, dass Sie einen Dateinamen verwenden, der mit der Codierung endet. Also für Textdateien, zum Beispiel, wäre dies so etwas wie README.ascii
, README.latin1
, README.utf8
usw.
Wenn Sie für Dateien, die eine bestimmte Erweiterung erfordern, die Codierung in der Datei selbst angeben können, z. B. in Perl oder Python, müssen Sie dies tun. Bei Dateien wie der Java-Quelle, in denen keine solche Funktion innerhalb der Datei vorhanden ist, setzen Sie die Codierung vor die Erweiterung, z SomeClass-utf8.java
.
Für die Ausgabe ist UTF-8 stark zu bevorzugen.
Für die Eingabe müssen wir jedoch herausfinden, wie wir mit den Tausenden von Dateien in unserer Codebasis namens umgehen sollen *.txt
. Wir möchten alle umbenennen, damit sie in unseren neuen Standard passen. Aber wir können sie unmöglich alle betrachten. Wir brauchen also eine Bibliothek oder ein Programm, das tatsächlich funktioniert.
Diese sind in ASCII, ISO-8859-1, UTF-8, Microsoft CP1252 oder Apple MacRoman erhältlich. Obwohl wir wissen, dass wir feststellen können, ob etwas ASCII ist, und wir wissen, ob es sich wahrscheinlich um UTF-8 handelt, sind wir über die 8-Bit-Codierungen ratlos. Da wir in einer gemischten Unix-Umgebung (Solaris, Linux, Darwin) arbeiten und die meisten Desktops Macs sind, haben wir einige nervige MacRoman-Dateien. Und das ist besonders ein Problem.
Seit einiger Zeit suche ich nach einer Möglichkeit, programmgesteuert zu bestimmen, welche davon
- ASCII
- ISO-8859-1
- CP1252
- MacRoman
- UTF-8
Eine Datei befindet sich in und ich habe kein Programm oder keine Bibliothek gefunden, die zuverlässig zwischen diesen drei verschiedenen 8-Bit-Codierungen unterscheiden kann. Wir haben wahrscheinlich allein über tausend MacRoman-Dateien, daher muss jeder Zeichensatzdetektor, den wir verwenden, in der Lage sein, diese herauszuspüren. Nichts, was ich mir angesehen habe, kann den Trick schaffen. Ich hatte große Hoffnungen auf die ICU-Zeichensatzdetektorbibliothek , aber sie kann nicht mit MacRoman umgehen. Ich habe mir auch Module angesehen, um in Perl und Python dasselbe zu tun, aber immer wieder ist es immer die gleiche Geschichte: Keine Unterstützung für die Erkennung von MacRoman.
Was ich daher suche, ist eine vorhandene Bibliothek oder ein Programm, das zuverlässig bestimmt, in welcher dieser fünf Codierungen sich eine Datei befindet - und vorzugsweise mehr. Insbesondere muss zwischen den drei von mir zitierten 3-Bit-Codierungen unterschieden werden, insbesondere zwischen MacRoman . Die Dateien bestehen zu mehr als 99% aus englischsprachigem Text. Es gibt einige in anderen Sprachen, aber nicht viele.
Wenn es sich um Bibliothekscode handelt, bevorzugen wir die Spracheinstellung in Perl, C, Java oder Python und in dieser Reihenfolge. Wenn es sich nur um ein Programm handelt, ist es uns egal, in welcher Sprache es sich befindet, solange es in voller Quelle vorliegt, unter Unix läuft und völlig unbelastet ist.
Hat jemand anderes das Problem gehabt, dass zig Millionen ältere Textdateien zufällig codiert wurden? Wenn ja, wie haben Sie versucht, es zu lösen, und wie erfolgreich waren Sie? Dies ist der wichtigste Aspekt meiner Frage, aber ich bin auch daran interessiert, ob Sie das Problem in Zukunft vermeiden können, wenn Sie Programmierer dazu ermutigen, ihre Dateien mit der tatsächlichen Codierung zu benennen (oder umzubenennen), in der sich diese Dateien befinden. Hat jemals jemand versucht, dies auf institutioneller Basis durchzusetzen, und wenn ja, war das erfolgreich oder nicht und warum?
Und ja, ich verstehe voll und ganz, warum man angesichts der Art des Problems keine eindeutige Antwort garantieren kann. Dies ist insbesondere bei kleinen Dateien der Fall, bei denen Sie nicht über genügend Daten verfügen, um fortzufahren. Glücklicherweise sind unsere Dateien selten klein. Abgesehen von der Zufallsdatei README
liegen die meisten im Größenbereich von 50.000 bis 250 KB, und viele sind größer. Alles, was größer als ein paar K ist, ist garantiert in Englisch.
Die Problemdomäne ist das biomedizinische Text Mining. Daher haben wir es manchmal mit umfangreichen und extrem großen Unternehmen zu tun, wie dem gesamten Open Access-Repository von PubMedCentral. Eine ziemlich große Datei ist der BioThesaurus 6.0 mit 5,7 Gigabyte. Diese Datei ist besonders ärgerlich, da es sich fast ausschließlich um UTF-8 handelt. Einige taubköpfige Personen haben jedoch ein paar Zeilen mit 8-Bit-Codierung eingefügt - Microsoft CP1252, glaube ich. Es dauert eine ganze Weile, bis Sie darauf stolpern. :((
Antworten:
Erstens die einfachen Fälle:
ASCII
Wenn Ihre Daten keine Bytes über 0x7F enthalten, handelt es sich um ASCII. (Oder eine 7-Bit-ISO646-Codierung, aber diese sind sehr veraltet.)
UTF-8
Wenn Ihre Daten als UTF-8 validiert sind, können Sie davon ausgehen, dass es sich um UTF-8 handelt. Aufgrund der strengen Validierungsregeln von UTF-8 sind Fehlalarme äußerst selten.
ISO-8859-1 gegen Windows-1252
Der einzige Unterschied zwischen diesen beiden Codierungen besteht darin, dass ISO-8859-1 die C1-Steuerzeichen enthält, wobei Windows-1252 die druckbaren Zeichen enthält. œžŸ. Ich habe viele Dateien gesehen, die geschweifte Anführungszeichen oder Bindestriche verwenden, aber keine, die C1-Steuerzeichen verwenden. Also kümmern Sie sich nicht einmal um sie oder ISO-8859-1, sondern erkennen Sie stattdessen nur Windows-1252.
Damit haben Sie nur noch eine Frage.
Wie unterscheidet man MacRoman von cp1252?
Das ist viel schwieriger.
Undefinierte Zeichen
Die Bytes 0x81, 0x8D, 0x8F, 0x90, 0x9D werden in Windows-1252 nicht verwendet. Wenn sie auftreten, nehmen Sie an, dass die Daten MacRoman sind.
Identische Zeichen
Die Bytes 0xA2 (¢), 0xA3 (£), 0xA9 (©), 0xB1 (±), 0xB5 (µ) sind in beiden Codierungen zufällig gleich. Wenn dies die einzigen Nicht-ASCII-Bytes sind, spielt es keine Rolle, ob Sie MacRoman oder cp1252 wählen.
Statistischer Ansatz
Zählen Sie die Zeichenfrequenzen (NICHT Byte!) In den Daten, von denen Sie wissen, dass sie UTF-8 sind. Bestimmen Sie die häufigsten Zeichen. Verwenden Sie dann diese Daten, um festzustellen, ob die Zeichen cp1252 oder MacRoman häufiger vorkommen.
Bei einer Suche, die ich gerade an 100 zufälligen englischen Wikipedia-Artikeln durchgeführt habe, sind die häufigsten Nicht-ASCII-Zeichen
·•–é°®’èö—
. Basierend auf dieser Tatsache,Zählen Sie die cp1252-vorschlagenden Bytes und die MacRoman-vorschlagenden Bytes hoch und wählen Sie das, was am größten ist.
quelle
Mozilla nsUniversalDetector (Perl-Bindungen: Encode :: Detect / Encode :: Detect :: Detector ) ist millionenfach bewährt.
quelle
x-mac-cyrillic
wird unterstützt,x-mac-hebrew
wird ausführlich in den Kommentaren besprochen,x-mac-anything-else
wird nicht erwähnt.Mein Versuch einer solchen Heuristik (vorausgesetzt, Sie haben ASCII und UTF-8 ausgeschlossen):
Randnotiz:
Mach das nicht!!
Der Java-Compiler erwartet, dass Dateinamen mit Klassennamen übereinstimmen. Wenn Sie die Dateien umbenennen, wird der Quellcode nicht kompilierbar. Das Richtige wäre, die Codierung zu erraten und dann mit dem
native2ascii
Tool alle Nicht-ASCII-Zeichen in Unicode-Escape-Sequenzen zu konvertieren .quelle
*.text
Dateien."Perl, C, Java oder Python und in dieser Reihenfolge": interessante Einstellung :-)
"Wir haben eine gute Veränderung, wenn wir wissen, ob es sich wahrscheinlich um UTF-8 handelt": Tatsächlich ist die Wahrscheinlichkeit, dass eine Datei mit aussagekräftigem Text, der in einem anderen Zeichensatz codiert ist, der Bytes mit hohen Bitmengen verwendet, erfolgreich dekodiert wird, da UTF-8 verschwindend klein ist.
UTF-8-Strategien (in der am wenigsten bevorzugten Sprache):
Sobald Sie entschieden haben, dass es weder ASCII noch UTF-8 ist:
Die mir bekannten Zeichensatzdetektoren mit Mozilla-Ursprung unterstützen MacRoman nicht und leisten auf keinen Fall gute Arbeit mit 8-Bit-Zeichensätzen, insbesondere mit Englisch, da sie AFAICT davon abhängen, zu prüfen, ob die Dekodierung im gegebenen Fall sinnvoll ist Sprache, ignoriert die Satzzeichen und basiert auf einer großen Auswahl von Dokumenten in dieser Sprache.
Wie andere angemerkt haben, stehen Ihnen nur die Satzzeichen mit hohem Bit-Satz zur Verfügung, um zwischen cp1252 und macroman zu unterscheiden. Ich würde vorschlagen, ein Modell vom Typ Mozilla an Ihren eigenen Dokumenten zu trainieren, nicht an Shakespeare oder Hansard oder der KJV-Bibel, und alle 256 Bytes zu berücksichtigen. Ich gehe davon aus, dass Ihre Dateien kein Markup (HTML, XML usw.) enthalten - das würde die Wahrscheinlichkeiten etwas Schockierendes verzerren.
Sie haben Dateien erwähnt, die meistens UTF-8 sind, aber nicht dekodiert werden können. Sie sollten auch sehr misstrauisch sein gegenüber:
(1) Dateien, die angeblich in ISO-8859-1 codiert sind, aber "Steuerzeichen" im Bereich von 0x80 bis einschließlich 0x9F enthalten ... dies ist so weit verbreitet, dass der Entwurf des HTML5-Standards vorschreibt, ALLE als ISO-8859 deklarierten HTML-Streams zu dekodieren -1 mit cp1252.
(2) Dateien, die OK als UTF-8 dekodieren, aber der resultierende Unicode "Steuerzeichen" im Bereich von U + 0080 bis einschließlich U + 009F enthält ... dies kann aus der Transcodierung von cp1252 / cp850 resultieren (gesehen!) / Etc. Dateien von "ISO-8859-1" bis UTF-8.
Hintergrund: Ich habe ein nasses Sonntagnachmittagsprojekt, um einen Python-basierten Zeichensatzdetektor zu erstellen, der dateiorientiert (anstatt
legacy ** n
weborientiert ) ist und gut mit 8-Bit-Zeichensätzen funktioniert, einschließlich solcher wie cp850 und cp437. Es ist noch lange nicht zur Hauptsendezeit. Ich interessiere mich für Trainingsdateien. Sind Ihre ISO-8859-1 / cp1252 / MacRoman-Dateien genauso "unbelastet", wie Sie es von einer anderen Codelösung erwarten?quelle
Wie Sie festgestellt haben, gibt es keinen perfekten Weg, um dieses Problem zu lösen, da ohne das implizite Wissen darüber, welche Codierung eine Datei verwendet, alle 8-Bit-Codierungen genau gleich sind: Eine Sammlung von Bytes. Alle Bytes sind für alle 8-Bit-Codierungen gültig.
Das Beste, auf das Sie hoffen können, ist eine Art Algorithmus, der die Bytes analysiert und basierend auf den Wahrscheinlichkeiten eines bestimmten Bytes, das in einer bestimmten Sprache mit einer bestimmten Codierung verwendet wird, errät, welche Codierung die Dateien verwenden. Das muss jedoch wissen, welche Sprache die Datei verwendet, und wird völlig unbrauchbar, wenn Sie Dateien mit gemischten Codierungen haben.
Wenn Sie wissen, dass der Text in einer Datei in Englisch geschrieben ist, ist es unwahrscheinlich, dass Sie einen Unterschied bemerken, unabhängig davon, welche Codierung Sie für diese Datei verwenden, da die Unterschiede zwischen allen genannten Codierungen alle lokalisiert sind die Teile der Codierungen, die Zeichen angeben, die normalerweise nicht in der englischen Sprache verwendet werden. Möglicherweise haben Sie Probleme, wenn der Text eine spezielle Formatierung oder spezielle Interpunktionsversionen verwendet (CP1252 enthält beispielsweise mehrere Versionen der Anführungszeichen), aber für den Kern des Textes gibt es wahrscheinlich keine Probleme.
quelle
Wenn Sie jede Codierung AUSSER für Makroman erkennen können, wäre es logisch anzunehmen, dass diejenigen, die nicht entschlüsselt werden können, in Makroman sind. Mit anderen Worten, erstellen Sie einfach eine Liste der Dateien, die nicht verarbeitet werden konnten, und behandeln Sie diese so, als wären sie makroman.
Eine andere Möglichkeit, diese Dateien zu sortieren, besteht darin, ein serverbasiertes Programm zu erstellen, mit dem Benutzer entscheiden können, welche Codierung nicht verstümmelt ist. Natürlich würde es innerhalb des Unternehmens sein, aber mit 100 Mitarbeitern, die jeden Tag ein paar erledigen, werden Sie Tausende von Dateien in kürzester Zeit fertig haben.
Schließlich wäre es nicht besser, alle vorhandenen Dateien in ein einziges Format zu konvertieren und zu verlangen, dass neue Dateien in diesem Format vorliegen.
quelle
Ich schreibe gerade ein Programm, das Dateien in XML übersetzt. Es muss den Typ jeder Datei automatisch erkennen, was eine Obermenge des Problems ist, die Codierung einer Textdatei zu bestimmen. Zur Bestimmung der Codierung verwende ich einen Bayes'schen Ansatz. Das heißt, mein Klassifizierungscode berechnet eine Wahrscheinlichkeit (Wahrscheinlichkeit), dass eine Textdatei eine bestimmte Codierung für alle Codierungen hat, die sie versteht. Das Programm wählt dann den wahrscheinlichsten Decoder aus. Der Bayes'sche Ansatz funktioniert für jede Codierung so.
Es stellt sich heraus, dass der Satz von Bayes sehr einfach zu machen ist, wenn Sie anstelle der Berechnung von Wahrscheinlichkeiten den Informationsgehalt berechnen , der der Logarithmus der Gewinnchancen ist :
info = log(p / (1.0 - p))
.Sie müssen die Initail-Priori-Wahrscheinlichkeit und die Korrelationen berechnen, indem Sie einen Korpus von Dateien untersuchen, die Sie manuell klassifiziert haben.
quelle