Problem mit Unicode... ;)

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
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

und schon wieder bastel ich ein wenig herum ;)

Habe nun ein Problem mit Unicode...


Ich möchte gerne eine Datei einlesen und mithilfe von blackbirds Tekisuto Parsen.

So alles ansich kein Problem... ;)

Ich habe aber ein Problem mit den Dateien, die ich einlesen möchte.

In welchem Encoding die gespeichert sind, weiß ich nicht. (wird leider auch in der praxis später so sein).

Nun möchte ich die in Unicode umwandeln (benötigt Tekisuto, zum arbeiten... ;) ).

Ich habe das so versucht:

Code: Alles auswählen

u''.join(r_data)
Aber ich bekomme im Enddefekt folgenden Fehler:

Code: Alles auswählen

Traceback (most recent call last):
  File "dauCMS.py", line 156, in ?
    main()
  File "dauCMS.py", line 137, in main
    dau_parser.parse_files()
  File "parser.py", line 190, in parse_files
    for token in self.lexer(u''.join(r_data)):
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
Der Relevante Teil im Code schaut so aus:

Code: Alles auswählen

# Inhalt einlesen
                r_data = open(self.project_path+data_file, 'r').read()

                try:
                    # Inhalt parsen
                    data = ''
                    for token in self.lexer(u''.join(r_data)):
                        data += token.data
Mache ich etwas grundsätzlich falsch oder schaue ich nur falsch? ;)


MfG EnTeQuAk
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

r_data = open(self.project_path+data_file, 'r').read()
Warum machst du das so? Wie soll die Datei jemals geschlossen werden? Nur wenn das Programm beendet wird, würde die Datei bei deiner Methode geschlossen werden.

So, wäre es besser:

Code: Alles auswählen

     f = open(self.project_path+data_file, 'r')
     
     try:
         # Inhalt parsen
         r_data = f.read()
         data = ''
         for token in self.lexer(u''.join(r_data)):
             data += token.data
         # An irgendeiner stelle in dieser Funktion explizit die Datei schließen!
         f.close()
Zu deinem Problem: Kann dein ``self.lexer`` mit Unicode umgehen? Gibt es da stellen wo du z.B. mit ``str`` umwandelst (Ja kling jetzt eigenartig, ich weiß ^^)

Das...

Code: Alles auswählen

str_ = u"üöß"
str2 = str(str_)
...ergibt das...

Code: Alles auswählen

    str2 = str(str_)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)
...weil ``str`` z.B. keine ``Unicode``-Objekte nach ``str``-Objekte umwandel kann.

Es könnte daher sein, dass irgendwelche Funktionen von dir etwas mit ``Unicode`` Strings machen, was die eben nicht können.

lg

P.S.: Gib mal bitte den Link zu der Datei zu deinem SVN-Repos. Möchte mir mal gerne die Methode anschauen.
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

Danke schonmal für die Tipps.
P.S.: Gib mal bitte den Link zu der Datei zu deinem SVN-Repos. Möchte mir mal gerne die Methode anschauen.

lexer.py
parser.py

lexer.py ist die Datei, die die Syntaxen definiert. Eigentlich nichts besonderes.

parser.py ist die Datei, die dann den gesamten Ablauf von dauCMS abarbeitet. Hier sind eigentlich erst die Zeilen ab Zeile 187 wichtig.


MfG EnTeQuAk
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Wieso ist die ``dauCMS.py`` noch nicht angepasst?

http://daucms.de/trac/browser/dauCMS/tr ... r=name#L65

Code: Alles auswählen

 dau_parser = MainParser(
	                        syntax_list = syntax_list,
	                        project = opts['project'],
	                        template = opts['template'],
	        )
Der Konstruktor von ``MainParser`` in ``parser.py`` sieht aber so aus:

Code: Alles auswählen

class MainParser:
	    def __init__(self, project, template, lexer):
Das ``keyword`` syntax_list gibt es also nicht im Konstruktor.

Ich würde gerne wissen was an den Parameter ``lexer`` übergeben wird (wir ja im self.lexer gespeichert). Wenn ich das erstmal weiß kann ich mir die Funktion/Klasse,was auch immer, anschauen (=Link).

Aber wie gesagt, ``dauCMS.py`` scheint irgendwie nicht auf den aktuellsten Stand zu sein, wegen dem oben genanten.

BTW: Irgendwas ist mit euren Server los. Der hat aussetzter.

lg
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

:D

Hoppla... vergessen zu sagem.

Immo arbeiten wir noch mit einem eigenen Lexer und Parser... und sind eben dabei mit Tekisuto rumzuspielen.

Die richtige Adresse, für die "aktuellen" spiel-dateien ist
http://daucms.de/trac/browser/dauCMS/tr ... order=name
Alles, was darüber ist, hat nichts mit diesem Thread zu tun :)

"BTW: Irgendwas ist mit euren Server los. Der hat aussetzter. "
ja, ja, ja :) das höre ich auch vom Team :) -- das liegt entweder an mod_python + Trac oder nur an Trac... aber das ist erstmal nebensächlich

MfG EnTeQuAk
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

EnTeQuAk hat geschrieben: Die richtige Adresse, für die "aktuellen" spiel-dateien ist
http://daucms.de/trac/browser/dauCMS/tr ... order=name
Alles, was darüber ist, hat nichts mit diesem Thread zu tun :)
Thx. Das sieht schon aktueller aus :D Ich stöbere mal ein wenig darum, da ich gerade Zeit und Lust habe. Mal schauen, vielleicht finde ich da den Fehler.

lg
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

Thx. Das sieht schon aktueller aus Very Happy Ich stöbere mal ein wenig darum, da ich gerade Zeit und Lust habe. Mal schauen, vielleicht finde ich da den Fehler.
Wunderbar... ich tue das auch schon seit einigen Stunden :) Bisher hab ich noch nichts richtiges gefunden.

Würde mich sehr freuen.


MfG EnTeQuAK
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

OK, allso ist der ``self.lexer``, der am Konstruktor von MainParser übergeben wird, ``DAUSyntax`` der eine Spezialisierung von ``BaseLexer`` in ``tekisuto.lexer.py`` ist.

...

So, das hätte ich mir aber auch sparen können weil ich den Fehler gefunden habe :)

Schau mal hier:

Code: Alles auswählen

str_ = "üöß"
str2 = u"".join(str_)

Code: Alles auswählen

   str2 = u"".join(str_)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)
Hier wird versucht ein ``join`` zumachen auf einen string der nicht Unicode ist, dessen Ergebnis aber Unicode sein muss (u"".) - (Ich hoffe man kann es einigermaßen verstehen)

Die Lösung sieht so aus:

Code: Alles auswählen

str_ = u"üöß"
str2 = u"".join(str_)
Das heißt, lese deine Datei im Unicode Modus ein, oder wandele das eingelesen in ein ``unicode``-Objkt um :)

Ich hoffe ich konnte helfen.

lg
sape
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:


Das heißt, lese deine Datei im Unicode Modus ein, oder wandele das eingelesen in ein ``unicode``-Objkt um Smile
Hmm...

mit dem umwandeln meinst du doch sicherlich:

Code: Alles auswählen

str_ = 'öÖäÄüÜ'
str2 = unicode(str_)
oda?

Das jedenfalls geht nicht.

Code: Alles auswählen

UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)
Und was meinst du mit als Unicode einlesen? -- Wie mache ich das?

Habe schon in der Doku gelesen, bei den methoden 'file()' und 'open()' aber direkt etwas gefunden.

Ich probiere gerade verschiedene Sachen mit der methode 'unicode()' aus... vllt. werde ich da fündig.

Danke auf jedenfall schonmal! :)


MfG EnTeQuAK
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Puh, bin nicht der Experte mit Unicode.

Ich habe das damals so gemacht:

Code: Alles auswählen

import codecs
f = codecs.open("c:\foobar.txt", "iso-8859-1")
Hab einfach die Dateien in "iso-8859-1" eingelesen.

lg

P.S.: Warte aber mal ab ob nicht jemand ne bessere Lösung hat. Vielleicht mal Birkenfeld oer BlackBird fragen wie die das mit dem Unicode sauber lössen (Irgendwas haben die sich bestimmt dafür gebaut) :)

BTW: Würde ich auch gerne wissen :D

lg
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

EnTeQuAk hat geschrieben: mit dem umwandeln meinst du doch sicherlich:

Code: Alles auswählen

str_ = 'öÖäÄüÜ'
str2 = unicode(str_)
oda?
Ne, das geht ja leider nicht (Weis auch nicht warum)

Ich meinte das so:

Code: Alles auswählen

str_ = "üöß"
str2 = str_.decode('utf-8')

EDIT:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys, codecs

stdout_encoding = sys.stdout.encoding or sys.getfilesystemencoding()

str_ = "üöß"
str2 = str_.decode('utf-8')
print str2.encode(stdout_encoding) # -> üöß
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

So... erweiternd dazu ;) Das Wiki... Ach ja... schön, das es das Gibt :)

[wiki]Von Umlauten, Unicode und Encodings[/wiki]

Da steht auch noch einiges drinne, was sehr interessant ist.


Bin aber trotzdem auf die anderen gespannt ;)

MfG EnTeQuAk


EDIT:

gerade deinen 'EDIT' gesehen ;) -- auch interessant. Werde mal alles nach und nach ausprobieren.
Zuletzt geändert von EnTeQuAk am Dienstag 23. Januar 2007, 19:37, insgesamt 1-mal geändert.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

EnTeQuAk hat geschrieben:So... erweiternd dazu ;) Das Wiki... Ach ja... schön, das es das Gibt :)
Jepp, von daher habe ich das auch ;)
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

EnTeQuAk hat geschrieben:Habe nun ein Problem mit Unicode...
Hi EnTeQuAk!

http://www.python-forum.de/post-30572.html ...falls du es noch nicht kennst. :-)

Das ist auch evt. nützlich, auch wenn es für ein spezielles Excel-Problem geschrieben wurde: http://www.python-forum.de/post-54734.html#54734

Diese beiden Links sollen dich generell über die Unicode-Problematik aufklären.

Es ist also zuerst mal wichtig, herauszufinden in welchem Coding der Quell-String vorhanden ist. -- Auch wenn man teilweise nur raten kann, aber raten ist immer noch besser als gar nichts tun.

Sobald das Quell-Encoding bekannt ist, ist es kein Problem mehr, nach Unicode umzuwandeln.

Folgende Encodings sind für den deutschsprachigen Raum interessant:
- iso-8859-1
- iso-8859-15
- mbcs
- cp850
- cp1252
Dann noch UTF-8 als Universal-Coding.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

Das ist verdammt interessant.

Ich habe nun folgendes eingefügt:

Code: Alles auswählen

                # Inhalt einlesen
                r_data = open(self.project_path+data_file, 'r').read()
                if not isinstance(r_data, unicode):
                    r_data = r_data.decode('iso-8859-1')
                else:
                    print 'nöööö'
Damit klappt das schonmal ein wenig weiter.

Nun bekomme ich einen weiteren Fehler in folgendem Code:

Code: Alles auswählen

                    try:
                        # geparsten Inhalt nach self.rendered_project_name schreiben
                        # FIXME: " data_file[:4] " -- it's not realy a good resolution...
                        # it's stupid if 'data_file' doesn't end with '.txt'
                        to_write = open(self.rendered_project_path+data_file[:-4]+'.html', 'w')
                        to_write.write(tmp_to_write)
                        to_write.close()
                    except Exception, e:
                        raise ParserError('Error while writing file %s ' % data_file,  e )
Der Fehler ist folgender:
(ein wenig durch eigene Fehlerklasse formatiert)

Code: Alles auswählen

parser.ParserError: 
An error is ocured:
Error while writing file dokumentation.txt 
'ascii' codec can't encode character u'\xe4' in position 970: ordinal not in range(128)
Um nachzuvollzieren, wo 'tmp_to_write' herkommt:

Code: Alles auswählen

 
                    if self.template_to_render == None:
                        tmp_to_write = data
                    else:
                        tmp_to_write = open('%s/templates/%s/%s.html' %(sys.path[0],\
                                                    self.template_to_render,\
                                                    self.template_to_render),'r').read()
So. Muss ich dort auch noch das Coding beachten?

Ein weiteres

Code: Alles auswählen

 if isinstance(r_data, str):
                            tmp_to_write = tmp_to_write.decode('iso-8859-1')
Für Weitere Informationen:
http://daucms.de/trac/browser/dauCMS/tr ... order=name

mfG EnTeQuAk
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

EnTeQuAk hat geschrieben:

Code: Alles auswählen

                # Inhalt einlesen
                r_data = open(self.project_path+data_file, 'r').read()
                if not isinstance(r_data, unicode):
                    r_data = r_data.decode('iso-8859-1')
                else:
                    print 'nöööö'
Hi EnTeQuAk!

Ich lese gar nicht weiter, dann hier liegt schon mal ein Fehler vor.
Wenn du mit ``open`` oder mit ``file`` eine Textdatei öffnest und einliest, dann hast du kein Unicode. Du hast einen Bytestring in irgendeiner Codierung. Welche das ist, hängt primär vom verwendeten Betriebssystem und von der Ländereinstellung ab. Unter einem deutschsprachigen Windows wird das wohl "cp1252" sein. Unter einem deutschsprachigen Linux meistens "iso-8859-1(5)" oder "UTF-8". Ein paar Dateien sind unter Windows auch UTF-16-codiert, aber die sind eher selten.

Du brauchst also nicht prüfen, ob du Unicode raus bekommst, denn da kommt kein Unicode raus. Unicode wird nur intern verwendet.

Versuche also erst mal das bevorzugte Encoding raus zu bekommen:

Code: Alles auswählen

import locale
print locale.getpreferredencoding()
Dann würde ich versuchen, mit Hilfe dieses bevorzugten Encodings, den Bytestring nach Unicode umzuwandeln:

Code: Alles auswählen

>>> f = file("J://Ablage//irgendeinedatei.txt", "r")
>>> bytestring = f.read()
>>> unicodestring = f.read().decode(locale.getpreferredencoding())
>>> f.close()
>>>
Erst wenn es dabei einen Fehler gibt, dann würde ich dem Benutzer ein paar Encodings in einer Combobox zur Auswahl präsentieren. Diese Auswahl würde ich in einer INI-Datei speichern und beim nächsten Mal zuerst das gespeicherte Encoding ausprobieren -- dann erst das ``preferredencoding``.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

...das hätte ich fast vergessen. :-)

Wenn du einen UNICODE-String hast und du möchtest diesen in eine Textdatei, mit dem für das Betriebssystem und dessen Ländereinstellung üblichen Encoding schreiben, dann bist du mit dem ``codecs``-Modul bestens bedient.

Code: Alles auswählen

>>> import codecs
>>> import locale
>>> f = codecs.open("J://Ablage//irgendeinedatei.txt", mode='w', encoding = locale.getpreferredencoding())
>>> f.write(u"löüäßßßß") # hier wissen wir genau, dass es ein UNICODE-String ist. :-)
>>> f.close()
>>>

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Antworten