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-1252
und iso8859-1
aufgrund 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- iconv
Tool 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"))