Python und Umlaute

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
Kilrathy
User
Beiträge: 5
Registriert: Freitag 17. Mai 2013, 14:15

So, nachdem ich 2 Stunden vergebens eine sinnvolle Lösung gesucht habe, brauch ich eure Hilfe.

Über ein Webformular in flask sende ich einige Informationen wie Namen und Standort in eine SQLite DB, das klappt soweit. Sobald aber ein Umlaut irgendwie vorkommt, fliegt Python halt auf die Fresse. Warum ist mir mehr oder weniger auch klar, kurz gesagt, Python geht immer von Unicode aus - und Umlaute passen dort nicht rein.

Somit will ich alle Umlaute verbannen, da aber der User vom Formular das nicht wissen muss, möchte ich vor dem DB Update die Umlaute üöä durch ue, oe und ae ersetzen.

Kann mir jemand helfen, wie ich das machen kann? Habe folgendes mal probiert in einem Testscript:

Code: Alles auswählen

s = u'über'
s.replace(u'ü', 'ue')

print s
Aber das gibt mir auch wieder einen Codierungsfehler aus:
UnicodeEncodeError: 'ascii' codec can't encode character u'\xfc' in position 0: ordinal not in range(128)
Danke und Gruss
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo Kilrathy,
sollte das Übertragen von Unicode-Strings von einem Webformular über flask nach SQLite nicht automatisch richtig funktionieren, machst Du irgendetwas falsch. Kannst Du mal Deinen Code posten.

Umlaute deshalb rauszuschmeißen ist auf jeden Fall der falsche Weg.
Zu Deinem Problem:
»s.replace« gibt einen neuen String zurück! »s« wird nicht geändert.
BlackJack

@Kilrathy: Mach Dir *wirklich* klar wo das konkrete Problem liegt und was es mit Bytes, Unicode, und Kodierungen auf sich hat.

Und dann verbanne keine Umlaute sondern verwende die Datentypen und Kodierungen korrekt. ASCII-only ist nicht mehr zeitgemäss. Python geht erst einmal von gar nichts aus. Und wenn Du Unicode als Datentyp verwendest, dann passen da nicht nur Umlaute rein, sondern alles mögliche was es an Zeichen in der Welt so gibt. Genau darum wurde Unicode eingeführt, um in einem Typen nicht immer nur die Untermenge einer 1-Byte-Kodierung haben zu können, wie das früher der Fall war. Wovon Python ausgeht ist ASCII als Kodierung wenn man zwischen Byte-Zeichenketten und Unicode-Zeichenketten umwandelt ohne eine Kodierung anzugeben. Das ist so weil man Kodierungen nicht zuverlässig automatisch ermitteln kann, und die Python-Entwickler die Sprache nicht raten lassen wollen.

Mach Dir klar und überprüfe was für Typen und Werte Du an welcher Stelle vor Dir hast. Wenn das Webrahmenwerk Unicode liefert, dann sollte SQLite damit gar keine Probleme haben, denn das Modul aus der Standardbibliothek kommt damit prima klar. Wenn das Webrahmenwerk kein Unicode liefert, wäre da ein Punkt anzusetzen und die Daten in Unicode umzuwandeln. Denn das ist der Datentyp mit dem man Texte intern verarbeiten sollte.

Dein Testskript funktioniert übrigens nicht weil die `replace()`-Zeile nichts bewirkt. Die gibt die veränderte Unicode-Zeichenkette zurück, aber Du machst damit dann gar nichst und gibst den ursprünglichen Wert *mit* Umlaut aus, der immer noch an den Namen `s` gebunden ist. Statt hier zu ersetzen, wäre es auch sinnvoller die Unicode-Zeichenkette vor der Ausgabe in eine Byte-Zeichenkette mit der Kodierung zu wandeln, die von dem Programm wo die ``print``-Ausgabe landet, erwartet wird. Also vom „anderen Ende” der `sys.stdout`-Datei.
Kilrathy
User
Beiträge: 5
Registriert: Freitag 17. Mai 2013, 14:15

Hallo zusammen

erst mal besten Dank für die Antworten, ich seh schon, ich muss mal zurück zum Start und mich echt mal mit diesen Kodierungen herumschlagen. Das mit dem Testscript ist wohl auch in meiner "Verzweiflung" entstanden... logisch dass hier nichts geht, weil ich die Variabel ja gar nicht veränder... :oops:

@Sirius3, beim aktuellen Fall sieht der Codeabschnitt so aus:

Code: Alles auswählen

@app.route('/show/all/')
@login_required
def show_all():
    g.db = connect_db()
    cur = g.db.execute('select patton_id, hostname, syslocation, ipaddress, \
        last_change from patton')

    patton_configs = [dict(hostname=row[1], syslocation=row[2],
                      ipaddress=socket.inet_ntoa(struct.pack('!L', row[3])),
                      last_change=unix2time(row[4]), patton_id=row[0])
                      for row in cur.fetchall()]

    for config in patton_configs:
        if len(config['syslocation']) > 60:
            config['syslocation'] = config['syslocation'][:60] + '...'
            print config['syslocation']
        else:
            print config['syslocation']

    g.db.close()
    return render_template('show_all.html', patton_configs=patton_configs)
Nach meinem heutigen Verständnis hole ich alle Records aus der DB und liste diese entsprechend auf. Mit einer kleinen if-Schleife kontrolliere ich die Länge von syslocation und trimme entsprechend. Ein Datensatz hat ein ä in der Syslocation weshalb flask mit der Meldung "UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' ...." - wenn ich das nun richtig interpretiere geht Python von ASCII aus und kann darum nichts damit anfangen.

Wie und wo deklariere ich am besten um welchen Datentyp es sich handelt? Weil sinnigerweise wäre ja (oder irre ich mich) Unicode überall zu verwenden, zumal dort wo ich Adressen, Namen oder sonstiges habe, wo alles mögliche an Zeichen auftretten kann.
BlackJack

@Kilrathy: Es gibt keine ``if``-Schleife!

Datentypen deklariert man in Python gar nicht. Man kann sie in Python auch gar nicht deklarieren.

Dein Problem hat nichts mit Flask zu tun, sondern dass Du versuchst mit ``print`` Unicode-Objekte auszugeben ohne sie zu kodieren. Das klappt nur wenn Python ermitteln kann was „am anderen Ende” von `sys.stdout` als Kodierung erwartet wird, oder wenn der Inhalt nur aus Zeichen im ASCII-Bereich besteht. Da hier `sys.stdout` eine Pipe zu einem anderen Programm sein wird, oder direkt eine Logdatei, gibt es keine vorgegebene Kodierung und darum gibt es die Ausnahme.
Kilrathy
User
Beiträge: 5
Registriert: Freitag 17. Mai 2013, 14:15

BlackJack, danke für die Info... warum ich if-Schleife geschrieben habe... keine Ahnung. Ich arbeite seit Jahren auf Linux und nutze nicht das erste mal eine if-Abfrage. :mrgreen:
Antworten