ubuntuusers.de

Skripte/Zeichensatzkonvertierung

Status: Ungelöst | Ubuntu-Version: Nicht spezifiziert
Antworten |
Dieses Thema ist die Diskussion des Artikels Skripte/Zeichensatzkonvertierung.

BillMaier Team-Icon

Supporter

Anmeldungsdatum:
4. Dezember 2008

Beiträge: 6499

Hallo,

hat jemand Lust hier python3 zu ergänzen?

Gruß BillMaier

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11289

Wohnort: München

Zu dem Thema kann man einiges schreiben - wenn jemand Verbesserungsvorschläge hat, nur zu ☺

In Python3 gibt es eine scharfe Trennung zwischen Bytestrings (bytes) und (Unicode-)Strings (str) - weiterführendes Lesematerial: https://docs.python.org/3/howto/unicode.html. Standardmäßig wird davon ausgegangen, dass (Quell)text in UTF-8 encodiert vorliegt und das wird normalerweise auch für die Ausgabe genutzt (wenn nichts anderes angegeben wurde). Der gängige Ablauf ist also Text zu decodieren, so dass man intern mit (Unicode-)Strings arbeiten kann und den Text für die Ausgabe wieder zu encodieren.

Bytestrings können unter Angabe des Encoding in (Unicode-)Strings überführt werden und umgekehrt (Zeichen, die nicht in ASCII darstellbar sind, müssen in Byte-Literals als Hex-Wert escaped geschrieben werden, das Ü in latin1 (ISO_8859-1) wäre 0xdc ⇒ b'\xdc'):

1
2
3
4
>>> b'\xdcberwald'.decode('latin1')
'Überwald'
>>> 'Überwald'.encode('latin1')
b'\xdcberwald'

Dateien kann man unter Angabe eines Encodings öffnen, dann erfolgt die Umwandung in Unicode für die Verarbeitung im Programm und das Encoding bei der Ausgabe in eine Datei automatisch - z.B. um von Windows-1252 explizit nach UTF-8 zu gehen und dabei die Zeilenenden passend für Linux zu setzen:

1
2
3
4
#!/usr/bin/env python3
with open('input.txt', 'r', encoding='windows-1252') as in_f, open('output.txt', 'w', encoding='utf-8') as out_f:
    for line in in_f:
        print(line.rstrip('\r\n'), end='\n', file=out_f)

Und wenn man als Argumente übergebene Dateien oder einen Stream von stdin, wobei die erwarteten Daten in ISO_8859-15 encodiert sind, decodieren und auf stdout ausgeben wollte, ginge das z.B. so:

1
2
3
4
#!/usr/bin/env python3
import fileinput
for line in fileinput.input(openhook=fileinput.hook_encoded("iso-8859-15")):
    print(line.rstrip('\r\n'))

Wenn man unbedingt mit dem "rohen" Inhalt von Dateien arbeiten will, kann man diese im Binär-Modus öffnen:

1
2
3
4
5
6
7
8
9
>>> with open('test.txt', 'wb') as f:
...     f.write('Überwald'.encode('iso-8859-15'))
...
>>> with open('test.txt', 'rb') as f:
...     f.read()
...
b'\xdcberwald'
>>> _.decode('windows-1252')
Überwald

Falls man das Encoding einer Datei nicht kennt, kann chardet (Pakete python-chardet bzw. python3-chardet) praktisch sein (das kann man auch direkt in Python nutzen: https://chardet.readthedocs.io/en/latest/usage.html):

$ chardet unknown_encoding.txt  # bzw. chardet3 wenn man die Variante für Python3 installiert hat
unknown_encoding.txt: ISO-8859-1 with confidence 0.73 

BillMaier Team-Icon

Supporter
(Themenstarter)

Anmeldungsdatum:
4. Dezember 2008

Beiträge: 6499

Danke, seahawk1986,

hier geht es ja nicht um eine vollständige Abhandlung der gesamten Thematik, sondern um ein oder zwei Beispiele - siehe die anderen Beispiele im Artikel. Wer will kann dann ja hier in der Diskussion (deinem Beitrag 😀 ) weiter lesen.

Gruß BillMaier

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11289

Wohnort: München

BillMaier schrieb:

hier geht es ja nicht um eine vollständige Abhandlung der gesamten Thematik, sondern um ein oder zwei Beispiele - siehe die anderen Beispiele im Artikel.

Unglücklicherweise funktionieren die Beispiele für Python 2 und Perl nicht ohne weiteres, sobald Zeichen ins Spiel kommen, die nicht aus dem ASCII-Zeichensatz stammen - so ganz ohne Erklärung ist das für Leute, die das erste mal mit der Problematik in Kontakt kommen vermutlich alles andere als hilfreich ...

Das Beispiel für Python2 funktioniert mit nicht-ASCII Zeichen nur dann, wenn der Quellcode in latin1 encodiert vorliegt und das in der Datei auch so deklariert wurde, also z.B.:

$ python2 < <(iconv -f utf-8 -t latin1 << EOF 
# -*- coding: iso-8859-1 -*-
print 'Überwald'.decode('latin1').encode('utf-8')
EOF
> )
Überwald 

Nicht-ASCII Zeichen im Quellcode sind bei Python2 nur erlaubt, wenn ein Encoding angeben wurde - lässt man den Kommentar weg, knallt es:

$ python2 < <(iconv -f utf-8 -t latin1 << EOF 
print 'Überwald'.decode('latin1').encode('utf-8')
EOF                                              
)
  File "<stdin>", line 1
SyntaxError: Non-ASCII character '\xdc' in file <stdin> on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details 

Und wenn man das Encoding der Datei korrekt deklariert (bzw. im REPL arbeitet), aber kein latin1 sondern wie beim heutigen Standard üblich UTF-8 mit Multibyte-Zeichen genutzt wird, bekommt man Blödsinn raus, weil man einen UTF-8 String als latin1 decodiert (dabei interpretiert es das 'Ü' als zwei 8-Bit Zeichen, die dann wieder als UTF-8 encodiert werden, weshalb dann 4 Bytes draus werden:

$ python2 << EOF | xxd                       
# -*- coding: utf-8 -*-
print 'Überwald'.decode('latin1').encode('utf-8')
EOF

00000000: c383 c29c 6265 7277 616c 640a            ....berwald. 

Das Beispiel für Perl 5 funktioniert auch nur, wenn latin1 für das Skript genutzt wird, denn Perl kann UTF-8 Multibyte-Zeichen im Quellcode nicht automatisch als solche erkennen, sondern behandelt die so als wären es zwei 8-Bit Zeichen, die dann einfach unverändert ausgegeben werden (mit use utf8; kann man Perl anweisen den Quellcode als UTF-8 zu interpretieren, aber wie man dann weitermacht, ist mir noch nicht ganz klar):

$ perl test_latin1_encoding.pl  | xxd
00000000: 4865 6c6c 6f20 57c3 b672 6c64 210a 4865  Hello W..rld!.He
00000010: 6c6c 6f20 57c3 b672 6c64 210a            llo W..rld!.
$ perl < <(iconv -f utf-8 -t latin1 test_latin1_encoding.pl) | xxd
00000000: 4865 6c6c 6f20 57f6 726c 6421 0a48 656c  Hello W.rld!.Hel
00000010: 6c6f 2057 f672 6c64 210a                 lo W.rld!. 

BillMaier Team-Icon

Supporter
(Themenstarter)

Anmeldungsdatum:
4. Dezember 2008

Beiträge: 6499

seahawk1986 schrieb:

Unglücklicherweise funktionieren die Beispiele für Python 2 und Perl nicht ohne weiteres, sobald Zeichen ins Spiel kommen, die nicht aus dem ASCII-Zeichensatz stammen - so ganz ohne Erklärung ist das für Leute, die das erste mal mit der Problematik in Kontakt kommen vermutlich alles andere als hilfreich ...

Hm, dann sollte das auch so geschrieben werden.

Oder "ausbaufähig" , oder macht die Seite dann so überhaupt Sinn?

Viele Grüße

BillMaier

noisefloor Team-Icon

Anmeldungsdatum:
6. Juni 2006

Beiträge: 29567

Hallo,

hier geht es ja nicht um eine vollständige Abhandlung der gesamten Thematik, sondern um ein oder zwei Beispiele - siehe die anderen Beispiele im Artikel.

Das funktioniert aber bei Python 3 nicht - siehe oben ☺

oder macht die Seite dann so überhaupt Sinn?

Ich würde sagen: nein. Die Beispiele Ruby, Perl und Python sind IMHO so wie so nicht "real life", weil die nur einen String, den man auch eintippen muss, wandeln.

Was wenn Sinn machen würden wer ein eigener Artikel zu iconv.

Gruß, noisefloor

BillMaier Team-Icon

Supporter
(Themenstarter)

Anmeldungsdatum:
4. Dezember 2008

Beiträge: 6499

Ergo archivieren wir diesen Artikel.

noisefloor Team-Icon

Anmeldungsdatum:
6. Juni 2006

Beiträge: 29567

Hallo,

ja, würde ich sagen.

Bzw. damit vielleicht noch ein bisschen warten. Ich denke, dass ich in der 1. Juli-Woche Zeit habe, was zu iconv zu schreiben. Dann ist der Übergang im Wiki "glatter".

Gruß, noisefloor

Antworten |