Wie konvertiere ich diesen String mit GNU / Linux-Tools in Japanisch?

2

Hier ist eine Zeichenfolge aus einer Textdatei:

@ ™ Tda®®ÆÆ ƒƒƒŒ ŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver Å Å Åjjjjjj

Es enthält viele nicht druckbare Zeichen und wird hier kopiert: https://pastebin.com/TUG4agN4

Verwenden https://2cyr.com/decode/?lang=de können wir bestätigen, dass es sich um Folgendes handelt:

☆ Tda 式 照 れ ミ ク ス ト ー ト ・ ビ キ ニ ニ 1 1 1 1 1 1 1 1 1 1 1 1

Dies ist mit Quellcodierung = SJIS (shift-jis), angezeigt als Windows-1252.

Aber wie können wir dasselbe Ergebnis ohne Website erzielen? Das relevante Werkzeug ist iconv, aber etwas in der Werkzeugkette ist defekt. Wenn ich versuche, aus der Quelltextdatei zu katzen oder sie als Standardeingabe mit '& lt;' in bash ist eines der 'iconv's in der kette schnell fehlerhaft. Wenn ich den obigen String aus dem Texteditor gedit (das Lesen der Datei als utf-16le) oder als Ausgabe von iconv mit utf16-to-utf8-Konvertierung kopiert, ist das Ergebnis zwar nahe, aber immer noch falsch:

@ 儺 式 式 れ ミ ミ ス ト ト [ト E ビ ビ 1 1 1 1d 1d 1d 1d 1 1 1 1 1 1 .1 .1 .1 .1 .1 .1 .1 .1 .1 .1 .1

Einige Beweise dafür, dass die Werkzeugkette versagt:

$ cat 'utf8.txt' | head -1

@ ™ Tda®®ÆÆ ~NƒƒƒƒŒ gŒŒŒrƒƒŒjŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver ver Å Å Å Å Å Å Å Å Å Å Å Å Å Å Å

$ cat 'utf8.txt' | head -1 | iconv -f utf8 -t utf16

@ "! Tda} ~ N X g R [ g E r L jver1.11d1.d2 i r L j f Ver9 ver.1.1 } z "z j

Beachten Sie beim Start drei ungültige Zeichen.

$ cat 'utf8.txt' | head -1 | iconv -f utf8 -t utf16 | iconv -f utf16 -t windows-1252

iconv: unzulässige Eingabesequenz an Position 2

$ echo "@ ™ Tda®® ® ~ ƒNƒXƒgƒŒ [ƒgEƒrƒLƒjver1.11d1.d2iƒrƒLƒjƒƒƒƒƒƒƒƒ verƒƒƒƒƒƒ verƒƒƒƒƒƒ verƒƒƒƒƒƒƒ verƒƒƒƒƒƒ ƒ ƒ ver ³ .1 ³” ”j" "" "" "" "" "" "" "" "" " iconv -f utf8 -t utf16

@ "! Tda} ~ N X gverR [ gE rverL jver1.11d1.d2i r L j f 9 ver.1.1 } z "z j

Beachten Sie beim Start zwei ungültige Zeichen, andere Unterschiede. Die vom Terminal kopierte Sequenz stimmt mit der im Texteditor angezeigten Zeichenfolge überein. Bestätigt wird dies mit übereinstimmender Suche (Strg-F). Dies ist die gleiche Zeichenfolge, die auf 2cyr.com das richtige Ergebnis liefert.

Wenn Sie den letzten Befehl mit '| iconv -f utf16 -t windows-1252 | iconv -f shift-jis -t utf8' erweitern, erhalten Sie das schließende, aber falsche Ergebnis, das oben zitiert wurde, und nicht wie bei der direkten Kette.

Wenn ich versuchte, eine Datei mit dem Namen "Beispielstring" zu erstellen und das Tool "convmv" darauf zu verwenden, sagte convmv, der Ausgabedateiname enthielt "Zeichen, die nicht dem POSIX-Dateisystem entsprechen. Die meisten Dateinamen, die mit UTF-8 ungültig sind, geben diese Warnung nicht aus.

Gibt es eine Bitsequenz, die das Piping in Bash nicht verarbeiten kann? Wenn nicht, warum funktioniert die Werkzeugkette nicht?

Anscheinend besteht der Unterschied darin, dass bash keine nicht gedruckten Zeichen (die Kästen mit Zahlen) in die Befehlszeile einfügt. vielleicht kann 'readline' nicht damit umgehen? Das Ergebnis der Annäherung legt jedoch nahe, dass die Konvertierungsreihenfolge in der Toolchain korrekt ist. Warum funktioniert sie dann nicht?

Die Originaldatei, deren Dateiname auf andere Weise verschlüsselt wurde (verfällt nach 30 Tagen): https://ufile.io/oorcq

Misaki
quelle

Antworten:

3

Pipes sind eine OS-Funktion, die mit Byte-Puffern arbeitet und deren Inhalt in keiner Weise interpretiert. Weitergeleiteter Text geht also nicht zu bash und insbesondere nie durch "readline". Text, der als Befehlszeilenargument eingefügt wird, tut dies. (Und ja, sowohl readline als auch das Terminal können als Sicherheitsmaßnahme Steuerzeichen ausfiltern.)

Ihre Datei ist eigentlich eine Mischung aus zwei Kodierungen, windows-1252 und iso8859-1Aufgrund der unterschiedlichen Möglichkeiten verwenden sie den C1-Steuerzeichenblock (0x80..0x9F).

  • ISO 8859-1 verwendet diesen gesamten Bereich für Steuerzeichen und die Bytes 0x80..0x9F entsprechen den Unicode-Codepunkten U + 0080..U + 009F.
  • Windows-1252 kann nicht C1 Steuerzeichen darstellen; Es verwendet den größten Teil dieses Bereichs für druckbare Zeichen und hat einige "Löcher" - d. h. Byte-Werte, denen nichts zugewiesen wurde (0x81, 0x8D, 0x8F, 0x90, 0x9D).
  • Ansonsten sind die beiden Kodierungen in den Bereichen 0x00..0x7F und 0xA0..0xFF identisch.

Nehmen wir die erste Zeile Ihrer "schlechten" Eingabedatei, dekodiert von UTF-16 in Unicode-Text und mit nicht druckbaren Zeichen mit Escape-Zeichen:

\u0081@\u0081™TdaŽ®\u008FÆ‚êƒ~ƒNƒXƒgƒŒ\u0081[ƒg\u0081EƒrƒLƒjver1.11d1.d2\u0081iƒrƒLƒjƒ‚ƒfƒ‹ver.1.1\u0090³Ž®”z•z”Å\u0081j\n
  • Du kannst sehen \u0081 (U + 0081), das dem Byte 0x81 in ISO 8859-1 zugeordnet wird, jedoch nicht in Windows-1252 codiert werden kann.
  • Sie können auch das Symbol sehen ƒ (U + 0192), das in Windows-1252 0x83 zugeordnet wird, in ISO 8859-1 jedoch überhaupt nicht vorhanden ist.

Der Trick ist also, wenn möglich, Windows-1252 und ISO 8859-1 als Fallback zu verwenden, wobei für jeden Codepoint individuell entschieden wird. (libiconv könnte dies über 'ICONV_SET_FALLBACKS') tun, aber über die CLI iconv Werkzeug kann nicht.) Es ist einfach, ein eigenes Werkzeug zu schreiben:

#!/usr/bin/env python3
with open("/dev/stdin", "rb") as infd:
    with open("/dev/stdout", "wb") as outfd:
        for rune in infd.read().decode("utf-16"):
            try:
                chr = rune.encode("windows-1252")
            except UnicodeEncodeError:
                chr = rune.encode("iso8859-1")
            outfd.write(chr)
            # outputs shift-jis

Beachten Sie nur das Hälfte von deinem Eingabedatei ist falsch codiertes Shift-JIS. Die andere Hälfte (Englisch) ist perfekt in UTF-16; Zum Glück wird Shift-JIS es durchlaufen, so dass kein manuelles Teilen erforderlich ist:

#!/usr/bin/env python3
with open("éΦé╟é▌üEé╓é╚é┐éσé▒éªéΦé⌐.txt", "r", encoding="utf-16") as infd:
    with open("りどみ・へなちょこえりか.txt", "w", encoding="utf-8") as outfd:
        buf = b""
        for rune in infd.read():
            try:
                buf += rune.encode("windows-1252")
            except UnicodeEncodeError:
                try:
                    buf += rune.encode("iso8859-1")
                except UnicodeEncodeError:
                    buf += rune.encode("shift-jis")
        outfd.write(buf.decode("shift-jis"))
grawity
quelle
Dies ist eine gute Lösung, die die Frage beantwortet, wie der ursprüngliche Text abgerufen wird. Meine Fragen sind diese:
Misaki
1) Gibt es eine Möglichkeit, die Originaldatei zu lesen, die keinen Rückfall auf eine zweite Kodierung beinhaltet? Ich gehe davon aus, dass es sich bei UTF-16 um etwas anderes handelt, weil ich versucht habe, es als andere Kodierungen in gedit zu öffnen. 2) Funktioniert diese Methode zum Lesen und Konvertieren eines Zeichens / einer "Rune" immer? Könnten 2-Byte-Zeichen falsch als 3-Byte- oder 1-Byte-Zeichen dekodiert werden, was zu einer "Rune" mit zu vielen oder zu geringen Informationen führt?
Misaki
3) Ist 2cyr.com gezwungen, denselben Fallback zu verwenden? Der String wird als UTF-8 an ihn gesendet, wenn ich verstehe, und bei der Auswahl der Decodierungseinstellungen wird weder UTF-16 noch ISO 8859-1 erwähnt. Es scheint ziemlich einfach zu sein, Kodierpaare wie SJIS + Windows-1252 zu testen, aber zu erkennen, dass auch UTF-16 involviert ist, erhöht die Komplexität.
Misaki
Einige dieser Kommentare sind möglicherweise irrelevant und können gelöscht werden. Ich glaube nicht, dass es ein Zufall ist, dass das fehlende Symbol 0x81 in Windows-1252 U + 0081 ist. Ich denke, dass der Texteditor, der die SJIS-Datei ursprünglich gelesen hatte, als Windows-1252 0x81 sah, sie nicht konvertieren konnte und sie dann einfach weitergab. Bei der Konvertierung von Unicode (beliebiger Art) nach Windows-1252 hat 2cyr dann eine ähnliche Aktion ausgeführt. & lt; del & gt; Ich vermute, U + 0081 ist nicht wirklich & lt; / del & gt; ok, es ist 0x0081 in UTF-16. Anstatt also der Fallback eine zweite Kodierung zu sein, wäre es die Rohbitfolge. Vielleicht wird davon ausgegangen, dass Sub-255 von Programmen sauber ist.
Misaki
Da U + 0081 in UTF8 0xC2 0x81 ist, wäre die Fallbitfolge der Unicode-Codepunkt.
Misaki