Probleme mit ASCII und Unicode in einem Python Script

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
CarlMcCoy
User
Beiträge: 3
Registriert: Dienstag 6. September 2011, 22:38

Hi Leute,

im Netz bin auf ein das GeekTool gestoßen, es ermöglicht den Desktop mit Skripten, Bildern oder Texten zu erweitern.
Beim stöbern an vorhandenen "Geeklets" bin ich auf ein Python Script gestoßen, welches eine XML-Datei einliest, analysiert und bestimmte Tags wieder ausgibt. In diesem Fall eine formatierte Ansicht der 1. Bundesliga.
Nun mein Problem, rufe ich das Script im Terminal auf, klappt die Ausgabe. Ich sehe die komplette Tabelle.
Über das Geektool sehe ich nur Platz 1-9. Ab Platz 10, Nürnberg, wird die Tabelle nicht mehr gezeigt. Ich habe das Skript in eine Text Datei umgelenkt und bekam folgenden Fehler:
"Traceback (most recent call last):
File "./bl-tabelle.py", line 30, in <module>
print "%3s %-20s %3s %4s %3s" % (position, name, played, goalDifference, points)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xfc' in position 5: ordinal not in range(128)"
Ich habe versucht etwas am coding bzw encoding zu drehen, damit das Script mit Umlauten umgehen kann, aber ich kenne mich mit Python rein gar nicht aus und hatte keinerlei Erfolg

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: latin-1 -*- <-Nachträglich von mir hinzugefügt

import urllib2
from xml.dom.minidom import parseString

hometeam="Hamburg" # Replace this with your team

url="http://www.footbo.com/widgets/xml/LeagueTable.aspx?id=193709"

file = urllib2.urlopen(url)
data = file.read()
file.close()
data = data.replace(hometeam, hometeam.upper())

#parse xml
dom = parseString(data)

print "POS CLUB                 PLD   GD PTS"

#loop through <entry> elements
entry=dom.getElementsByTagName('LeagueTableRow')
for node in entry:
    position=node.getAttribute('Position')
    name=node.getAttribute('TeamName')
    played=node.getAttribute('GamesPlayed')
    goalDifference=node.getAttribute('GoalsDifference')
    points=node.getAttribute('Points')

    print "%3s %-20s %3s %4s %3s" % (position, name, played, goalDifference, points)
Wie würde man mit einfachen Mitteln das hinbekommen, das folgende Ausgabe erfolgt und die Umlaute auch korrekt ausgegeben werden?

Code: Alles auswählen

POS CLUB                 PLD   GD PTS
  1 Bayern                 4    8   9
  2 Schalke 04             4    4   9
  3 Werder                 4    4   9
  4 Hannover               4    2   8
  5 Gladbach               4    3   7
  6 Dortmund               4    3   7
  7 Mainz 05               4    1   7
  8 Bayer 04               4    0   7
  9 Hoffenheim             4    1   6
 10 Nürnberg               4   -1   6
 11 Hertha                 4    0   5
 12 Stuttgart              4    1   4
 13 Freiburg               4    0   4
 14 1.FC Köln              4   -6   4
 15 Wolfsburg              4   -4   3
 16 Augsburg               4   -3   2
 17 Lautern                4   -5   2
 18 HAMBURG                4   -8   1
System ist Mac OS X 10.7, Python 2.7.1
Über Tipps bzw. Hilfe wäre ich sehr dankbar.

Mit freundlichen Grüßen
CarlMcCoy
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ist die Datei denn überhaupt in latin-1 codiert? Generell finde ich ja utf-8 am sinnvollsten...

Du könntest mal gucken, ob position, name usw. Unicode-Objekte sind (`print type(name)` davor einfügen z.B.). Wenn ja, ändere mal diese Zeile so um:

Code: Alles auswählen

print u"%3s %-20s %3s %4s %3s" % (position, name, played, goalDifference, points)
Man beachte das "u" vor dem Anführungszeichen.

Sollte das immer noch zu Murks führen, musst Du das Encoding für Deine Konsole noch einstellen:

Code: Alles auswählen

result = u"%3s %-20s %3s %4s %3s" % (position, name, played, goalDifference, points)
print result.encode("dein gewünschtes encoding")
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
CarlMcCoy
User
Beiträge: 3
Registriert: Dienstag 6. September 2011, 22:38

Hi Hyperion,

vielen, vielen Dank!!
Die Erweiterung um:

Code: Alles auswählen

result = u"%3s %-20s %3s %4s %3s" % (position, name, played, goalDifference, points)
print result.encode("dein gewünschtes encoding")
hat geholfen!
Jetzt wird die Tabelle sowohl im Terminal, als auch im Geektool und beim umleiten in eine Textdatei richtig dargestellt.

Gruß
CarlMcCoy
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Schön, dass es funktioniert, aber eigentlich löst das das Problem nicht. Eigentlich gibt es auch kein Problem, denn bei mir funktioniert das Beispiel. Ich sehe Köln um Umlaut auf Platz 14.

Statt mittels trial & error irgendwelche Encodings zu ändern, sollte man verstehen, wie es funktioniert.

Eine XML-Datei kennt ihr Encoding, welches im Header angegeben ist. Standardmäßig ist es UTF-8. Somit ist das streng genommen keine Text-Datei, sondern eine Binärdatei. Jeder anständige XML-Parser (auch der bei Python eingebaute) kommt damit klar und kann dann String-Objekte (vom Typ unicode) erzeugen. Die XML-Datei aus dem Beispiel ist korrekt UTF-8-kodiert, gibt es im Header an und trägt sogar einen BOM.

Welches Encoding die Python-Datei hat, ist irrelevant. Das würde nur String-Konstanten mit Zeichen außerhalb des ASCII-Bereichs betreffen bzw. bei Python 3 auch die Namen der Variablen, die dort aus allen Buchstaben, die der Unicode-Standard kennt bestehen dürfen.

OS/X kommt garantiert auch unter Lion im Terminal damit klar (ich habe hier noch Snow Leopard), String-Objekte korrekt darzustellen. Das Terminal nimmt standardmäßig UTF-8 an und das weiß auch Python unter OS/X. Da dürfte es auch keine Probleme geben. Wichtig ist natürlich, dass man auch Strings (und keine Byte-Arrays vom Typ str) ausgibt. Aber das macht der Original-Code auch, denn type("%s" % u"foobar") ist wieder unicode.

Stefan
CarlMcCoy
User
Beiträge: 3
Registriert: Dienstag 6. September 2011, 22:38

Schön, dass es funktioniert, aber eigentlich löst das das Problem nicht. Eigentlich gibt es auch kein Problem, denn bei mir funktioniert das Beispiel. Ich sehe Köln um Umlaut auf Platz 14.

Statt mittels trial & error irgendwelche Encodings zu ändern, sollte man verstehen, wie es funktioniert.

Eine XML-Datei kennt ihr Encoding, welches im Header angegeben ist. Standardmäßig ist es UTF-8. Somit ist das streng genommen keine Text-Datei, sondern eine Binärdatei. Jeder anständige XML-Parser (auch der bei Python eingebaute) kommt damit klar und kann dann String-Objekte (vom Typ unicode) erzeugen. Die XML-Datei aus dem Beispiel ist korrekt UTF-8-kodiert, gibt es im Header an und trägt sogar einen BOM.

Welches Encoding die Python-Datei hat, ist irrelevant. Das würde nur String-Konstanten mit Zeichen außerhalb des ASCII-Bereichs betreffen bzw. bei Python 3 auch die Namen der Variablen, die dort aus allen Buchstaben, die der Unicode-Standard kennt bestehen dürfen.

OS/X kommt garantiert auch unter Lion im Terminal damit klar (ich habe hier noch Snow Leopard), String-Objekte korrekt darzustellen. Das Terminal nimmt standardmäßig UTF-8 an und das weiß auch Python unter OS/X. Da dürfte es auch keine Probleme geben. Wichtig ist natürlich, dass man auch Strings (und keine Byte-Arrays vom Typ str) ausgibt. Aber das macht der Original-Code auch, denn type("%s" % u"foobar") ist wieder unicode.

Stefan
Hi Stephan,

das Terminal war auch nicht das Probelm. Die Darstellung innerhalb des Terminals war zu jederzeit korrekt. Es ging um die Ausgabe in Geektool. In diesem Zusammenspiel gab es Probleme mit dem Coding. Die Darstellung brach bei Nürnberg auf Grund des U-Umlauts ab.
Aber Danke für deinen Hinweis.
Du als Mac-User solltest dir mal Geektool ansehen! Macht richtig spaß und erweitert deinen Schreibtisch mit allem was Du möchtest.
Zu beziehen über den App-Store.
Hier ein paar Eindrücke was machbar ist: http://desktopspotting.com/25/awesome-g ... x-desktop/

Gruß
CarlMcCoy
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Geektool gefällt vielen. Ich mag meinen Bildschirm aufgeräumt und leer. Darüber habe ich dann zwei oder drei Fenster, die eh den Bildschirm komplett füllen. Eine Uhrzeit habe ich auch oben rechts, Systeminformationen wie den Füllstand der Festplatte oder Fussballergebnisse ;) brauche ich nicht laufend im Blick.

Das Problem war also, dass Geektool Shell-Mode nicht UTF-8 verstanden hat, was Python ausgegeben hat?

Stefan
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

sma hat geschrieben: Aber das macht der Original-Code auch, denn type("%s" % u"foobar") ist wieder unicode.
Ach verdammt... das hatte ich doch glatt anders im Kopf. Danke für den Hinweis! Wenn man selber auf konsequente Unicodebenutzung im Code achtet, dann vergisst man solche Sachen wohl wieder :oops:
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@sma: IMHO ist aber das kodieren als Bytestrings vor der Ausgabe im Allgemeinen immer notwendig, auch wenn Python die Kodierung vom Terminal kennt. Denn spätestens wenn man die Ausgabe in ein anderes Programm pipe't oder in eine Datei umlenkt, gibt es keine implizite Kodierung mehr und die Ausgabe von Unicode-Zeichenketten funktioniert mit Zeichen ausserhalb von ASCII nicht mehr.
Antworten