Wie konvertiert man diesen String mit GNU / Linux-Tools in Japanisch?

511
Misaki

Hier ist eine Zeichenfolge aus einer Textdatei:

@ ™ 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 Å Å Å Åjjj j

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

Mit https://2cyr.com/decode/?lang=en können wir bestätigen, dass es sich wie folgt übersetzt:

☆ Tda 式 照 れ ミ ク ス ト ー ト ・ ビ キ ニ ニ 1 1 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 '<' in der Bash zu verwenden, wird 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 1d 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ŒƒverjŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ 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 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®®Æ ~ ~ ~ ƒXƒƒ gE ƒƒ verververververververververververver.d.d.d.d.d.d.d.d.d 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.1 ³ ³ ³ ³” ”” "" "" "" "" "" "" "" "" "" "" ”” ” iconv -f utf8 -t utf16

@ "! Tda} ~ N X g R [ 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, die von find (ctrl-F) gefunden wird. 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 nahe, aber unkorrekte Ergebnis, das oben zitiert wurde.

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. Dies kann zu Datenverlust führen." 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

2

1 Antwort auf die Frage

3
grawity

Pipes sind eine OS-Funktion, die mit Byte-Puffern arbeitet und deren Inhalt in keiner Weise interpretiert. Weitergeleiteter Text geht also nicht durch Bash und vor allem niemals 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-1252und 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 keine C1-Steuerzeichen darstellen. Es verwendet den größten Teil dieses Bereichs für druckbare Zeichen und hat einige "Löcher" - dh 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 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 
  • Sie können \u0081(U + 0081) sehen, welche das Byte 0x81 in ISO 8859-1 darstellt, aber in Windows-1252 nicht codiert werden kann.
  • Sie können auch das Symbol ƒ(U + 0192) sehen, das in Windows-1252 0x83 zugeordnet ist, 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, das CLI- iconvTool jedoch nicht.) Es ist einfach, ein eigenes Tool 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, dass nur die Hälfte Ihrer Eingabedatei Shift-JIS falsch codiert ist. 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")) 
Dies ist eine gute Lösung, die die Frage beantwortet, wie der ursprüngliche Text abgerufen wird. Meine Fragen sind diese: Misaki vor 6 Jahren 0
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 vor 6 Jahren 0
3) Ist 2cyr.com gezwungen, denselben Fallback zu verwenden? Die Zeichenfolge wird als UTF-8 gesendet, wenn ich das 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 und mein Verständnis ist schlecht genug, dass ich nicht ganz sicher bin, dass dies getan werden muss. Misaki vor 6 Jahren 0
Einige dieser Kommentare sind möglicherweise irrelevant und können gelöscht werden. Ich denke 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 hat, als Windows-1252 0x81 erkannt hat, 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.Ich vermute, U + 0081 ist eigentlich nichtok, 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 vor 6 Jahren 0
Da U + 0081 in UTF8 0xC2 0x81 ist, wäre die Fallbitfolge der Unicode-Codepunkt. Misaki vor 6 Jahren 0
@Misaki: 1) Ja, UTF-16 ist beteiligt (Ihre Datei ist 100% UTF-16), aber auch nach der UTF-16-Dekodierung enthält die erste Hälfte unsinnige Daten und diese Konvertierung ist unvermeidlich. 2) Es funktioniert _ wie gezeigt_ - jeder Unicode-Runen- / Codepunkt wird einem nützlichen Element zugeordnet; In Ihrer Eingabedatei können 100% von ihnen jeweils einem einzelnen Byte zugeordnet werden. Sie sind jedoch auch richtig, dass sie nicht einer _ Whole_ Shift-JIS-Sequenz zugeordnet werden kann, weshalb mein Beispiel bis zum Ende wartet, um den gesamten Puffer schließlich als Shift-JIS zu decodieren. Die sofortige Verwendung von rune.encode ("windows-1252"). Decode ("shift-jis") würde sehr schnell fehlschlagen. grawity vor 6 Jahren 0
@Misaki: 3) Ich würde davon ausgehen. "Wenn dies fehlschlägt, versuchen Sie es mit ISO 8859-1" ist ein ziemlich verbreiteter Ansatz. Wenn Sie den Text an 2cyr.com senden, ist UTF-16 nicht mehr beteiligt. Ihr Texteditor hat UTF-16 bereits für Sie entschlüsselt. Der Browser verschlüsselt den übermittelten Text in UTF-8 und der Server decodiert ihn. Dies ist jedoch ein transparentes Detail. grawity vor 6 Jahren 0
@Misaki: Wie die Datei ursprünglich erstellt wurde, "sah 0x81 nicht, konnte sie nicht konvertieren und dann einfach weitergeben" - das könnte wahr sein, aber _also_ könnte auch als Fallback nach ISO 8859-1 interpretiert werden 0x81 ist in der Tat auf U + 0081 abgebildet. (Wie ich schon sagte, diese Art von Fallback ist sehr verbreitet ...) grawity vor 6 Jahren 0