Konvertierung iso latin 1 --> utf8

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Mareike
User
Beiträge: 4
Registriert: Samstag 19. Januar 2013, 19:11

Hallo,

Ich parse mit python 3.3 Textdateien, die im (oktal) isolatin1-Format vorliegen.
Dabei erhalte ich Strings, wobei die Sonderzeichen als ASCII-Codierungen enthalten sind.
so zB "\133Unit\135" anstatt "[Unit]".

Jetzt ist meine Frage wie ich den String kovertieren muss, damit die ASCII Codierung in das entsprechende Charakter umgewandelt wird.

Die Konsole wandelt richtig um:

Code: Alles auswählen

>>> text="\133Hz\135"
>>> print(text)
[Hz]
In meinem Programm wird weiterhin die ASCII-Codierung ausgegeben.

Code: Alles auswählen

        self.fobj = codecs.open(filename, 'r','latin_1');
        
        self.fobj_out = codecs.open(savefile,"w","UTF-8")

            text = self.fobj.read()
            result = re.finditer(r,text,re.I)
            for line in result:
                self.fobj_out.write(str(i)+ str(line.group(1)) +"\n")
                
                i=i+1
                
            self.fobj.close()
            self.fobj_out.close()
Kann mir jemand helfen wie ich das umwandeln kann?

Grüße,
Mareike
BlackJack

@Mareike: Die Einrückung bei Deinem Quelltext stimmt nicht.

Dateien sollte man mit der ``with``-Anweisung verwenden. Ich vermute mal ganz stark es macht keinen Sinn die beiden Dateien an das Objekt zu binden. Also weg mit dem `self`.

Die literale Zeichenkette in der Python-Shell wird vom Python-Compiler interpretiert, die Daten die durch Dein Programm verarbeitet werden nicht. Eine Zeichenkette die Ziffern in einem Zahlensystem wie zum Beispiel Oktal enthalten kann man mit der `int()`-Funktion in eine Zahl umwandeln. Und eine Zahl, die einen Unicode-Codepoint enthält kann man mit der `chr()`-Funktion in eine Zeichenkette umwandeln, die das dazugehörige Zeichen enthält. Mit dem `re`-Modul kann man einen regulären Ausdruck formulieren der die Escapesequenzen mit den Oktalzahlen findet, und mit der `sub()`-Funktion/-Methode kann man in Zeichenketten mit regulären Ausdrücken suchen und ersetzen. Für die Ersetzung kann man auch eine Funktion angeben, die für jeden Treffer mit einem `Match`-Objekt aufgerufen wird, und eine Zeichenkette zurück gibt, durch die der Treffer ersetzt werden soll. Diese Puzzleteile muss man jetzt nur noch zu einem Programm zusammensetzen. :-)
cmax
User
Beiträge: 14
Registriert: Dienstag 22. Januar 2013, 21:36

f = open(filename, 'rb')
bs = f.read()
f.close()
s = bs.decode('ISO-8859-1').encode('utf8').decode('unicode_escape')
print(s)
BlackJack

@cmax: Wobei das mehr umwandelt als nur oktale Escapes.
Mareike
User
Beiträge: 4
Registriert: Samstag 19. Januar 2013, 19:11

@Blackjack: Danke für die schnelle Antwort. Der Codeausschnitt ist Teil einer etwas umfangreicheren tkinter-GUI, daher das "self" und die fehlerhafte Einrückung. int() und chr() Funktionen hab ich schon getestet, würde die Lösung allerdings gerne hinten anstellen, da die Textdateien sehr viele Kontrollsequenzen enthalten...

@cmax: hab ich auch schon versucht:
string.encode('utf-8').decode('latin_1')
Allerdings bekomm ich hierbei für Python 3.X die Fehlermeldung:
"AttributeError: 'str' object has no attribute 'decode'".

Gehts nicht was ähnliches in python 3?

Grüße,
Mareike
cmax
User
Beiträge: 14
Registriert: Dienstag 22. Januar 2013, 21:36

BlackJack hat geschrieben:@cmax: Wobei das mehr umwandelt als nur oktale Escapes.
Stimmt. Das könnte je nach Text zu Problemen führen. :(

@Mareike:

Mein Code ist für Python3.

Deine Fehlermeldung ist insofern verständlich, dass str (in Python3) nicht decodiert werden kann - ist er ja schon.
Aber eigentlich sollte string.encode('utf-8') doch eine Instanz von bytes zurückliefern. :?
Mareike
User
Beiträge: 4
Registriert: Samstag 19. Januar 2013, 19:11

cmax hat geschrieben: @Mareike:

Mein Code ist für Python3.

Deine Fehlermeldung ist insofern verständlich, dass str (in Python3) nicht decodiert werden kann - ist er ja schon.
Aber eigentlich sollte string.encode('utf-8') doch eine Instanz von bytes zurückliefern. :?
Ja, stimmt, wenn es alleine steht:
<class 'bytes'>

Ich dachte bisher wenn ich

Code: Alles auswählen

self.fobj = codecs.open(filename, 'r','latin_1')
ausführe, interpretiert Python den latin-string automatisch nach Unicode.

Grüße,
Mareike
BlackJack

@Mareike: cmax hat die Daten als Bytes eingelesen und Du lässt sie beim Einlesen schon dekodieren. Bei ``string.encode('utf-8').decode('latin_1')`` kann die von Dir behauptete Fehlermeldung unter Python 3.x nicht kommen. `string` muss vom Typ `str` sein und nach dem `encode()` hast Du ein Objekt vom Typ `bytes`, und *das* hat ganz sicher eine `decode()`-Methode. Der Ausdruck macht in Deinem Kontext aber auch gar keinen Sinn, denn wenn `string` eine korrekte Unicode-Zeichenkette ist, dann kommt da „Müll” bei heraus. Zumindest wenn etwas ausserhalb von ASCII enthalten ist.

Edit: Das `self` bei den Dateiobjekten macht keinen Sinn. Falls Du das anders siehst, könntest Du mal erklären warum man geschlossene Dateiobjekte auf dem Objekt haben möchte auf dem die Methode existiert.

Und falls Du die `re.sub()`-Lösung mit `int()` und `chr()` nicht nimmst, weil Du denkst das könnte zu langsam sein: Das wage ich zu bezweifeln. Wenn Du damit leben kannst, das 'unicode-escape' mehr als nur Oktalzahlen-Escapesequenzen ersetzt, dann ist das natürlich trotzdem die einfachere Lösung.
Mareike
User
Beiträge: 4
Registriert: Samstag 19. Januar 2013, 19:11

@Blackjack:

Habs jetzt so gemacht, wie von dir empfohlen. Klappt wirklich gut :D Vielen Dank! Muss ich jetzt mal für verschiedene Dateien testen. Wobei ich immer noch nicht versteh, warum das mit der Codierung nicht funktioniert... naja, mal wieder kostenlose Lebenszeit verschwendet :wink:

Wegen dem self-Objekt:

Code: Alles auswählen

class Application(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        
    def createWidgets(self)
    ...
    def konvert (self):
    ...
root = tk.Tk()
app = Application(master=root)
app.mainloop()
Das ist das Grundgerüst meiner GUI, und ich speicher alle Variablen in dem self-objekt. Warum ich das mache, keine Ahnung, war in irgendeinem Programmbeispiel aus der Python-Doc... :mrgreen: Lasse mich aber gerne belehren :)

Grüße,
Mareike
BlackJack

@Mareike: Du speicherst nicht alle Objekte als Attribute. `text`, `result`, `line`, und `i` zum Beispiel nicht. Warum also die Dateiobjekte? Auf ein Objekt gehört alles was den Zustand des Objektes ausmacht als Attribut. Und zwar sollten alle Attribute nach Abarbeitung der `__init__()`-Methode existieren, denn diese Methode initialisiert den Zustand eines Objektes und das sollte danach vollständig initialisiert sein. Wenn in anderen Methoden neue Attribute hinzugefügt werden, dann gehören die da in aller Regel nicht hin und irgend etwas am Entwurf ist falsch oder zumindest fragwürdig.

Und wenn innerhalb einer Methode das `self`-Argument überhaupt nicht verwendet wird, dann ist auch etwas komisch. Denn dann ist die Methode eigentlich gar keine Methode und man sollte sich Fragen warum eine normale Funktion in eine Klasse gesteckt wurde. Falls es dafür einen Grund gibt, sollte man den dokumentieren. Im DocString, aber mindestens dadurch, dass man `staticmethod()` als „decorator” verwendet.
Antworten