[nicht gelöst] Problem mit Codierung

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
basti33
User
Beiträge: 56
Registriert: Donnerstag 24. August 2006, 15:05

Hallo,

ich habe versucht einen Vokabeltrainer zu schreiben und scheitere jetzt daran, dass ich meine Vokabeln aufgrund von Codierungsproblemen nicht abfragen lassen kann. Der Inhalt der Datei, in der ich Vokabeln speichere, sieht auch nicht wirklich nach Unicode aus. Ich poste mal, was Kate mir zeigt:
S'das Gleiche'
p33
aVla m�e
p34
aa.
Mich wundert vor allem dieses Fragezeichen. Weil ich wirklich überhaupt keine Ahnung habe, wo der Fehler sitzt, poste ich hier mal das ganze Skript und hoffe, jemand macht sich die Mühe das anzusehen.

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-    #Das sollte doch eigentlich alles in Unicode lesen und speichern, oder?

# Vokabeltrainer 1.1.1

# by basti33

from Tkinter import *
from time import sleep
from sys import exit
from cPickle import *
from tkFileDialog import *
from random import randint
from tkMessageBox import *

def Hauptmenue(): #Hier wird das Hauptmenu instanziert
    # Hier werden die Buttons des Startfensters definiert
    global Startfenster
    Startfenster=Tk(className='Willkommen-Vokabeltrainer 1.1')
    Startfenster.focus_set()
    Startfenster.geometry("+300+300")
    Begruessungstext=Label(Startfenster, text='Willkommen beim Vokabeltrainer 1.1\nWähle bitte einen Modus', font=("Sans", 12, "bold"))
    Button1=Button(Startfenster, text='Neue Vokabeldatei anlegen', command=NenneVokFile, font=("Sans", 12))
    Button2=Button(Startfenster, text='Vokabeldatei erweitern', command=EditVokFile, font=("Sans", 12))
    Button3=Button(Startfenster, text='Vokabeln abfragen', command=DoF, bg='#EE9A00', activebackground='#EE9A00', font=("Sans", 12))
    Button4=Button(Startfenster, text='Vokabeldateien zusammenführen')#, command=VereinigeVok)
    Button5=Button(Startfenster, text='Beenden', command = lambda: exit(), font=("Sans", 12))
    # Hier werden die Buttons des Startfensters gepackt
    Begruessungstext.pack()
    Button1.pack()
    Button2.pack()
    Button3.pack()
    #Button4.pack()
    Button5.pack()
    Startfenster.mainloop()
       
def NenneVokFile():
    global Vokabeldatei
    Vokabeldatei=asksaveasfilename(initialdir='/home/basti/Vokabelfiles', filetypes=[("Vokabeldateien", "*.vok")])
    if len(Vokabeldatei) > 4:
        NeueVok(Vokabeldatei)

def EditVokFile():
    global Vokabeldatei
    Vokabeldatei=askopenfilename(initialdir='/home/basti/Vokabelfiles', filetypes=[('Vokabeldateien', '*.vok')])
    if len(Vokabeldatei) != 0:
        Startfenster.destroy()
        NeueVok(Vokabeldatei)

def NeueVok(Vokabeldatei):
    # In dieser Funktion wird der Dialog zum Speichern neuer Vokabeln definiert
    # Hier werden die einzelnen Elemente des Fenster definiert
    global Unterfenster, Eingabefeld1, Eingabefeld2
    try:
        Startfenster.destroy()
    except:
        pass
    Unterfenster=Tk(className='Neue Vokabeln - Vokabeltrainer 1.1')
    Unterfenster.geometry("+300+300")
    Unterfenster.focus_set()
    Fremdsprache=Label(Unterfenster, text='Gib hier die Vokabel in der Fremdsprache ein: ', font=("Sans", 12))
    Deutsch=Label(Unterfenster, text='Gib hier die deutsche Übersetzung ein: ', font=("Sans", 12))
    Eingabefeld1=Entry(Unterfenster, font=("Sans", 12))
    Eingabefeld1.focus_set()
    Eingabefeld2=Entry(Unterfenster, font=("Sans", 12))
    Eingabefeld2.bind('<KeyPress-Return>', SpeicherVok)
    HM=Button(Unterfenster, text='Hauptmenü', command=Zurueck, font=("Sans", 12)) #HM steht für Hauptmenü
    # Hier wird das Ganze ins Layout gebracht
    Fremdsprache.grid(column=0, row=0)
    Eingabefeld1.grid(column=1, row=0)
    Deutsch.grid(column=0, row=1)
    Eingabefeld2.grid(column=1, row=1)
    HM.grid(column=1, row=2)
    Unterfenster.mainloop()
    
def SpeicherVok(event):
    # Diese Funktion speichert die Vokabeln, die in NeueVok eingegeben worden sind
    FE=Eingabefeld1.get() # FE steht für fremdsprachliche Eingabe
    DE=Eingabefeld2.get() # DE steht für deutsche Eingabe
    try:
        f=file(Vokabeldatei, 'r')
        up=Unpickler(f)
        geladeneVok=up.load()
        geladeneVok.append([DE, FE])
        f=file(Vokabeldatei, 'w')
        p=Pickler(f)
        p.dump(geladeneVok)
        f.close()
    except IOError:
        f=file(Vokabeldatei, 'w')
        p=Pickler(f)
        p.dump([[DE, FE]])
        f.close()
    weiter2()
    
def weiter2(): #Weiter 2 wird benutzt um nach dem Speichern der Vokabel neue eingeben zu können
    Unterfenster.destroy()
    NeueVok(Vokabeldatei)
    
def DoF():  #DoF fragt ab, in welcher Richtung die Vokabeln gefragt werden sollen und ob Zeit miteinbezogen werden soll
    global Fragefenster, Zeiteingabe, Frage1
    Fragefenster=Tk(className='Einstellungen')
    Fragefenster.geometry("+300+300")
    Fragefenster.focus_set()
    Zeit=Checkbutton(Fragefenster, text='Intensivtraining', command=IoZ, font=("Sans", 12)) #IoZ steht für Intensiv oder Zeit
    Zeiteingabe=Entry(Fragefenster, state=DISABLED, font=("Sans", 12))
    Frage1=Label(Fragefenster, text='Gib die Zeit (in Minuten) an, in der Vokabeln abgefragt werden sollen: ', state=DISABLED, font=("Sans", 12))
    Frage2=Label(Fragefenster, text='Welche Sprache?', font=("Sans", 12))
    DF=Button(Fragefenster, text='Deutsch-Fremdsprache', command=lambda: OeffneVok(0), font=("Sans", 12))
    FD=Button(Fragefenster, text='Fremdsprache-Deutsch', command=lambda: OeffneVok(1), font=("Sans", 12))
    Zeit.grid(column=0, row=0)
    Frage1.grid(column=1, row=0)
    Zeiteingabe.grid(column=2, row=0)
    Frage2.grid(column=1, row=1)
    DF.grid(column=0, row=2)
    FD.grid(column=1, row=2)
    Zeit.select()
    Fragefenster.mainloop()
    
def IoZ(): # Diese Funktion graut bei Bedarf die Felder Zeiteingabe und Frage1 aus
    if Zeiteingabe.cget('state') == 'disabled':
        Zeiteingabe.config(state=NORMAL)
        Frage1.config(state=NORMAL)
    else:
        Zeiteingabe.config(state=DISABLED)
        Frage1.config(state=DISABLED)

def OeffneVok(Sprache):
    global Vokabeldatei, MySprache, Wartezeit
    try:
        Wartezeit=int(Zeiteingabe.get())
    except ValueError:
        Wartezeit=0
    Fragefenster.destroy()
    MySprache=Sprache
    Vokabeldatei=askopenfilename(initialdir='/home/basti/Vokabelfiles', filetypes=[('Vokabeldateien', '*.vok')])
    if len(Vokabeldatei) != 0:
        Startfenster.destroy()
        LadeVok(Vokabeldatei, MySprache)

def LadeVok(Vokabeldatei, MySprache):
    # Diese Funktion wählt eine Vokabel aus der Liste aus und stellt sie zur Weiterbearbeitung zur Verfügung
    # Zunächst wird die Datei geladen
    global Antwortfeld, VokabelListe, alleVok, Unterfenster, RoF
    f=file(Vokabeldatei, 'r')
    up=Unpickler(f)
    VokabelListe=up.load()
    laenge=len(VokabelListe) #Hier wird die Länge der Vokabelliste ermittelt
    alleVok=randint(0, laenge)-1 #Hier wird per Zufall eine Vokabel ausgewählt. Es wird eine Zahl abgezogen, da randint bei 1, die Liste jedoch bei 0 zu zählen beginnt
    Vokabel=VokabelListe[alleVok][MySprache]    #Alle Vok=Ergebniss aus alleVok, MySprache= 0 oder 1 je für die Sprache
    # Hier wird das Fenster definiert, das später den Ausfragedialog führt
    try:
        Startfenster.destroy()
    except TclError:
        pass
    Unterfenster=Tk(className='Vokabelabfrage - Vokabeltrainer 1.1')
    Unterfenster.geometry("+300+300")
    Unterfenster.focus_set()
    ZeigeVokabel=Label(Unterfenster, text=Vokabel, font=("Sans", 12))
    Aufforderung=Label(Unterfenster, text='Schreibe hier die Übersetzung: ', font=("Sans", 12))
    Antwortfeld=Entry(Unterfenster, font=("Sans", 12))
    Antwortfeld.bind('<KeyPress-Return>', UeberpruefeAnt) #bindet Enter an die Funktion UeberpruefeAnt
    Antwortfeld.focus_set()
    HM=Button(Unterfenster, text='Hauptmenü', command=Zurueck, font=("Sans", 12))
    RoF=Label(Unterfenster) # RoF steht für Richtig oder Falsch
    ZeigeVokabel.grid(column=1, row=0)
    Aufforderung.grid(column=0, row=1)
    Antwortfeld.grid(column=1, row=1)
    HM.grid(column=0, row=2)
    RoF.grid(column=1, row=2)
    Unterfenster.mainloop()
    
def UeberpruefeAnt(event):     # Überprüft, ob die Antwort richtig oder falsch ist und reagiert dem entsprechend
    global Ergebniss, Nachrichtenfenster
    Antwort = Antwortfeld.get()
    Antwortfeld.delete(0, END)  #löscht den Text im Eingabefeld
    if MySprache==0:    #Hier ist der Teil für DF
        if Antwort != VokabelListe[alleVok][1]: #Falsch
            Nachrichtenfenster=Tk(className='Falsch!')
            Nachrichtenfenster.geometry("+300+300")
            Nachrichtenfenster.focus_set()
            Nachricht=Label(Nachrichtenfenster, text='Falsch! Richtig wäre: '+VokabelListe[alleVok][1], fg='#EE0000', font=("Sans", 12))
            Nachrichtenfenster.bind('<KeyPress-Return>', weiter)
            Nachricht.pack()
            Nachrichtenfenster.mainloop()
        else:   #Richtig
            weiter1()
    else:   # Und hier der Teil für FD
        if Antwort != VokabelListe[alleVok][0]: #Falsch
            Nachrichtenfenster=Tk(className='Falsch!')
            Nachrichtenfenster.geometry("+300+300")
            Nachrichtenfenster.focus_set()
            Nachricht=Label(Nachrichtenfenster, text='Falsch! Richtig wäre: '+VokabelListe[alleVok][0], fg='#EE0000', font=("Sans", 12))
            Nachrichtenfenster.bind('<KeyPress-Return>', weiter)
            Nachricht.pack()
            Nachrichtenfenster.mainloop()
        else:   #Richtig
            weiter1()

def weiter(event):  # weiter wird aufgerufen falls die Antwort falsch war
    Nachrichtenfenster.destroy()
    Unterfenster.destroy()
    LadeVok(Vokabeldatei, MySprache)

def weiter1():  # weiter1 wird aufgerufen falls die Antwort richtig war
    Unterfenster.destroy()
    sleep(Wartezeit*60)
    LadeVok(Vokabeldatei, MySprache)

def Zurueck(): # Diese Funktion dient dazu, aus einer beliebigen Funktion ins Hauptmenü zurückzukommen
    Unterfenster.destroy()
    Hauptmenue()
    
Hauptmenue()
Der Fehler, den ich immer angezeigt bekomme ist folgender

Code: Alles auswählen

Exception in Tkinter callback
Traceback (most recent call last):
  File "lib-tk/Tkinter.py", line 1348, in __call__
    return self.func(*args)
  File "Vokabeltrainer 1_1_1.py", line 184, in UeberpruefeAnt
    Nachricht=Label(Nachrichtenfenster, text='Falsch! Richtig wäre: '+VokabelListe[alleVok][1], fg='#EE0000', font=("Sans", 12))
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 17: ordinal not in range(128)
Bitte verlinkt mich nicht auf irgendeine der Hilfeseiten, ich versteh das irgendwie nicht. Bitte zeigt mir einfach was falsch ist, davon lern ich am besten!

Danke!

PS: Ich benutze eric und als Kodierung ist auch hier utf-8 eingestellt
Zuletzt geändert von basti33 am Sonntag 5. November 2006, 15:24, insgesamt 1-mal geändert.
BlackJack

Das hat erst einmal gar nichts mit den gespeicherten Daten zu tun. Tk will Unicode-Zeichenketten haben. Du übergibst in der Zeile aber eine Byte-Zeichenkette und die versucht Python als ASCII zu dekodieren. Das klappt nicht, weil ein ä drin vorkommt und zwar wie die Ausnahmemeldung sagt, an Position 17 der Bytewert 0xc3:

Code: Alles auswählen

In [34]: 'Falsch! Richtig wäre: '[17]
Out[34]: '\xc3'
Mach da einfach eine Unicode-Zeichenkette draus indem Du ein 'u' vor die Zeichenkette setzt. Die Kodierung im "Kodierungskommentar" wird dann benutzt um die Bytes in der Quelltextdatei zu dekodieren.
basti33
User
Beiträge: 56
Registriert: Donnerstag 24. August 2006, 15:05

Danke für die Antwort. Ganz klar ist mir der Fehler aber noch immer nicht. Ich verstehe nicht, warum der Fehler nur dann auftritt, wenn die Vokabel selbst ein Umlaut enthält und warum das Problem gerade hier sitzt, wo Tkinter doch an anderen Stellen auch Umlaute anzeigt (z.B. bei "Wähle bitte einen Modus").

Danke

Edit: Außerdem erhalte ich jetzt als Lösung keine korrekte Vokabel sondern ein Zeichenwirrwar.
BlackJack

basti33 hat geschrieben:Danke für die Antwort. Ganz klar ist mir der Fehler aber noch immer nicht. Ich verstehe nicht, warum der Fehler nur dann auftritt, wenn die Vokabel selbst ein Umlaut enthält und warum das Problem gerade hier sitzt, wo Tkinter doch an anderen Stellen auch Umlaute anzeigt (z.B. bei "Wähle bitte einen Modus").
Was die Stellen voneinander unterscheidet ist das addieren der Zeichenketten. Anscheinend wandelt Tkinter eine Zeichenkette in UTF-8 selbst korrekt um. Wenn Du eine Zeichenkette mit einer Unicode-Zeichenkette "addierst", dann wird die Zeichenkette in Unicode umgewandelt, und dabei wird von ASCII ausgegangen:

Code: Alles auswählen

In [39]: 'Falsch! Richtig wäre: ' + u'foo'
---------------------------------------------------------------------------
exceptions.UnicodeDecodeError    Traceback (most recent call last)

/home/marc/<ipython console>

UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 17: ordinal not in range(128)
Antworten