So erraten Sie zuverlässig die Codierung zwischen MacRoman, CP1252, Latin1, UTF-8 und ASCII


99

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 *.txtoder 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.utf8usw.

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

  1. ASCII
  2. ISO-8859-1
  3. CP1252
  4. MacRoman
  5. 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 READMEliegen 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:


86

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,

  • Die Bytes 0x92, 0x95, 0x96, 0x97, 0xAE, 0xB0, 0xB7, 0xE8, 0xE9 oder 0xF6 schlagen Windows-1252 vor.
  • Die Bytes 0x8E, 0x8F, 0x9A, 0xA1, 0xA5, 0xA8, 0xD0, 0xD1, 0xD5 oder 0xE1 legen MacRoman nahe.

Zählen Sie die cp1252-vorschlagenden Bytes und die MacRoman-vorschlagenden Bytes hoch und wählen Sie das, was am größten ist.


6
Ich habe Ihre Antwort akzeptiert, weil sich kein besserer präsentiert hat, und Sie haben gute Arbeit geleistet, um genau die Themen aufzuschreiben, an denen ich herumgebastelt hatte. Ich habe in der Tat Programme, um diese Bytes aufzuspüren, obwohl Sie ungefähr die doppelte Anzahl haben, die ich mir ausgedacht habe.
Tchrist

10
Endlich kam es dazu, dies umzusetzen. Es stellt sich heraus, dass Wikipedia keine guten Trainingsdaten sind. Aus 1k zufälligen en.wikipedia-Artikeln, ohne den Abschnitt SPRACHEN, habe ich 50.000 unASCII-Codepunkte erhalten, aber die Verteilung ist nicht glaubwürdig: mittlerer Punkt und Aufzählungszeichen sind zu hoch, & c & c & c. Also habe ich den All-UTF8-PubMed-Open-Access-Korpus verwendet und + 14M unASCII-Codepunkte abgebaut. Ich verwende diese, um ein Relativfrequenzmodell aller 8-Bit-Codierungen zu erstellen, das schicker als Ihre ist, aber auf dieser Idee basiert. Dies ist ein starker Hinweis auf die Kodierung für biomedizinische Texte, die Zieldomäne. Ich sollte das veröffentlichen. Vielen Dank!
Tchrist

5
Ich habe noch keine MacRoman-Dateien, aber die Verwendung von CR als Zeilenbegrenzer wäre kein nützlicher Test. Dies würde für ältere Versionen von Mac OS funktionieren, obwohl ich nicht über OS9 weiß.
Milliways

10

Mozilla nsUniversalDetector (Perl-Bindungen: Encode :: Detect / Encode :: Detect :: Detector ) ist millionenfach bewährt.


Weitere Dokumentation finden Sie hier: mozilla.org/projects/intl/detectorsrc.html. Wenn Sie sich in die Dokumente vertiefen, finden Sie die unterstützten Zeichensätze
Joel Berger,

@ Joel: Ich habe mich in die Quelle eingegraben. Es war eine rhetorische Frage. x-mac-cyrillicwird unterstützt, x-mac-hebrewwird ausführlich in den Kommentaren besprochen, x-mac-anything-elsewird nicht erwähnt.
John Machin

@ John Machin: Seltsam, dass Kyrilliker und Hebräer ein Nicken bekommen, aber sonst nichts. Ich warf nur eine andere Dokumentationsquelle ein, ich hatte nicht weiter gelesen, danke dafür!
Joel Berger

7

Mein Versuch einer solchen Heuristik (vorausgesetzt, Sie haben ASCII und UTF-8 ausgeschlossen):

  • Wenn 0x7f bis 0x9f überhaupt nicht angezeigt werden, handelt es sich wahrscheinlich um ISO-8859-1, da dies sehr selten verwendete Steuercodes sind.
  • Wenn 0x91 bis 0x94 häufig angezeigt werden, handelt es sich wahrscheinlich um Windows-1252, da dies die "intelligenten Anführungszeichen" sind, bei weitem die wahrscheinlichsten Zeichen in diesem Bereich, die im englischen Text verwendet werden. Um sicherer zu sein, könnten Sie nach Paaren suchen.
  • Ansonsten ist es MacRoman, besonders wenn Sie viele 0xd2 bis 0xd5 sehen (dort befinden sich die typografischen Anführungszeichen in MacRoman).

Randnotiz:

Bei Dateien wie der Java-Quelle, in denen keine solche Funktion innerhalb der Datei vorhanden ist, setzen Sie die Codierung vor die Erweiterung, z. B. SomeClass-utf8.java

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 native2asciiTool alle Nicht-ASCII-Zeichen in Unicode-Escape-Sequenzen zu konvertieren .


7
Dummes Kompilor! Nein, wir können den Leuten nicht sagen, dass sie nur ASCII verwenden können. Das sind nicht mehr die 1960er Jahre. Es wäre kein Problem, wenn es eine @ Encoding-Annotation gäbe, damit die Tatsache, dass sich die Quelle in einer bestimmten Codierung befindet, nicht außerhalb des Quellcodes gespeichert werden muss, ein wirklich idiotisches Manko von Java, unter dem weder Perl noch Python leiden . Es sollte in der Quelle sein. Das ist jedoch nicht unser Hauptproblem. Es sind die Tausenden von *.textDateien.
Tchrist

3
@tchrist: Es wäre eigentlich gar nicht so schwer, einen eigenen Annotationsprozessor zu schreiben, um eine solche Annotation zu unterstützen. Immer noch ein peinliches Versehen, es nicht in der Standard-API zu haben.
Michael Borgwardt

Selbst wenn Java @encoding unterstützen würde, würde dies nicht sicherstellen, dass die Codierungsdeklaration korrekt ist .
Dan04

4
@ dan04: Sie können dasselbe über die Codierungsdeklaration in XML, HTML oder anderswo sagen. Aber genau wie bei diesen Beispielen, wenn es in der Standard-API definiert wäre, würden die meisten Tools, die mit Quellcode arbeiten (insbesondere Editoren und IDEs), dies unterstützen, was ziemlich zuverlässig verhindern würde, dass Benutzer versehentlich Dateien erstellen, deren Inhaltscodierung nicht übereinstimmt die Erklärung.
Michael Borgwardt

4
"Der Java-Compiler erwartet, dass Dateinamen mit Klassennamen übereinstimmen." Diese Regel gilt nur, wenn die Datei eine öffentliche Klasse der obersten Ebene definiert.
Matthew Flaschen

6

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

# 100% Unicode-standard-compliant UTF-8
def utf8_strict(text):
    try:
        text.decode('utf8')
        return True
    except UnicodeDecodeError:
        return False

# looking for almost all UTF-8 with some junk
def utf8_replace(text):
    utext = text.decode('utf8', 'replace')
    dodgy_count = utext.count(u'\uFFFD') 
    return dodgy_count, utext
    # further action depends on how large dodgy_count / float(len(utext)) is

# checking for UTF-8 structure but non-compliant
# e.g. encoded surrogates, not minimal length, more than 4 bytes:
# Can be done with a regex, if you need it

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 ** nweborientiert ) 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?


1
Der Grund für die Sprachreihenfolge ist die Umgebung. Die meisten unserer Hauptanwendungen befinden sich in Java und die Nebenprogramme, und einige Anwendungen befinden sich in Perl. Wir haben hier und da ein bisschen Code, der in Python ist. Ich bin meistens ein C- und Perl-Programmierer, zumindest nach erster Wahl, also suchte ich entweder nach einer Java-Lösung zum Einstecken in unsere App-Bibliothek oder nach einer Perl-Bibliothek für dieselbe. Wenn C, könnte ich eine XS-Klebeschicht erstellen, um sie mit der Perl-Schnittstelle zu verbinden, aber das habe ich noch nie in Python gemacht.
Tchrist

3

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.


1

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.


5
Komisch! Als ich diesen Kommentar zum ersten Mal las, nachdem ich 30 Minuten lang unterbrochen worden war, las ich "macroman" als "macro man" und stellte keine Verbindung mit MacRoman her, bis ich nach dieser Zeichenfolge gesucht hatte, um festzustellen, ob das OP sie erwähnt hatte
Adrian Pronk

+1 Diese Antwort ist irgendwie interessant. Ich bin mir nicht sicher, ob es eine gute oder eine schlechte Idee ist. Kann sich jemand eine vorhandene Codierung vorstellen, die möglicherweise auch unentdeckt bleibt? wird es wahrscheinlich in Zukunft eine geben?
Benutzername

1

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?

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.

  1. Legen Sie die anfängliche ( vorherige ) Wahrscheinlichkeit fest, dass sich die Datei in der Codierung befindet, basierend auf den Häufigkeiten jeder Codierung.
  2. Untersuchen Sie nacheinander jedes Byte in der Datei. Suchen Sie den Bytewert, um die Korrelation zwischen dem vorhandenen Bytewert und einer Datei zu ermitteln, die sich tatsächlich in dieser Codierung befindet. Verwenden Sie diese Korrelation, um eine neue ( hintere ) Wahrscheinlichkeit zu berechnen, dass sich die Datei in der Codierung befindet. Wenn Sie mehr Bytes untersuchen müssen, verwenden Sie die hintere Wahrscheinlichkeit dieses Bytes als vorherige Wahrscheinlichkeit, wenn Sie das nächste Byte untersuchen.
  3. Wenn Sie am Ende der Datei angelangt sind (ich sehe mir eigentlich nur die ersten 1024 Bytes an), ist die Wahrscheinlichkeit, die Sie haben, die Wahrscheinlichkeit, dass sich die Datei in der Codierung befindet.

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.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.