Seite 1 von 1
geloest - unicode problem
Verfasst: Dienstag 9. Dezember 2008, 09:21
von xWolf
Hallo,
Mein Problem ist das Einlesen von Zeichen aus einer Datei, die uniocode-Zeichen enthalten.
Mein code-Schnipsel:
Code: Alles auswählen
Datensatz = u""
AnzahlBytes = 270
# Position errechnen
.
.
self.f_obj.seek(Position,0) #................Zeiger positionieren
Datensatz = unicode(self.f_obj.read(AnzahlBytes)) #...Datensatz lesen
Dabei erhalte ich den Fehler:
Code: Alles auswählen
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 143: ordinal not in range(128)
Wie bringe ich python bei, dass ich die eingelesenen Zeichen in eine Variable des Types: "unicode" speichern kann?
Danke euch.
Wolf
Verfasst: Dienstag 9. Dezember 2008, 09:40
von Lonestar
hi, ich tu mich immer noch ein wenig schwer mit encodings, und hoffe mal ich verzapfe hier nu keinen Unsinn - aber das sieht für mich so aus als wenn du kein Unicode aus deiner Datei einlesen würdest.
Wenn du die Datei einfach direkt mit passendem Encoding öffnest sollte sich dein Problem eigentlich erledigen - Hilfe gibts im WIKI [wiki]Von Umlauten, Unicode und Encodings[/wiki]ganz unten
Verfasst: Dienstag 9. Dezember 2008, 10:15
von Leonidas
Du gibst kein Encoding an, welches deine Daten haben, also nimmt Python ASCII an, was natürlich crasht, wenn deine Dateien eben nicht durch ASCII repräsentierbar sind.
Verfasst: Dienstag 9. Dezember 2008, 10:19
von xWolf
Leonidas hat geschrieben:Du gibst kein Encoding an, welches deine Daten haben, also nimmt Python ASCII an, was natürlich crasht, wenn deine Dateien eben nicht durch ASCII repräsentierbar sind.
Danke,
Hast Du 'nen Tipp, wie ich das encoding angebe?
Wolf
Verfasst: Dienstag 9. Dezember 2008, 10:33
von Leonidas
Als zweiten Parameter zu ``unicode()`` oder als 1. Parameter zu ``"string".decode()``.
Verfasst: Dienstag 9. Dezember 2008, 10:43
von Darii
Over du verwendest
codecs.open
Verfasst: Dienstag 9. Dezember 2008, 10:56
von xWolf
Lonestar hat geschrieben:hi, ich tu mich immer noch ein wenig schwer mit encodings, und hoffe mal ich verzapfe hier nu keinen Unsinn..
Hallo,
Danke fuer den Tipp. Unsinn war das auf keinen Fall. Es hat geklappt, nur hast Du mir ein neues Problem beschehrt.
Und zwar lese ich Datensaetze mit einer bestimmten Laenge in Bytes aus der Datei. Dass klappt auch. Aber nachdem ich den Datensatz gelesen habe, teile ich den Satz in zwei Datenfelder mittels Stringfunktionen wie:
Code: Alles auswählen
Datenfeld1 = Datensatz[0:80]
Datenfeld2 = Datensatz[80:]
Nun kommt der Haken. Vorher waren es ASCII-Zeichen und die Laenge des Strings war auch die Anzahl der Ascii-Zeichen. Nun werden aber bei der Codierung zwei Zeichen zu einem Zeichen zusammengefasst. Somit haut die Teilung des Datensatzes in zwei Felder mittels Zeichenzaehlung per Stringfunktionen nicht mehr hin.
Kennst Du eine Funktion, die nicht die Zeichen sondern die Anzahl Bytes einer Variable zaehlt?
Danke.
Wolf
Verfasst: Dienstag 9. Dezember 2008, 11:14
von Hyperion
Darf man fragen, um was für Daten es da in der Datei geht? Scheint mir ja eine obskure Mischung aus Binär und Textdaten zu sein? Kennst Du das Format näher? Evtl. gibt es ja einen besseren Weg, das zu parsen ...
Verfasst: Dienstag 9. Dezember 2008, 11:24
von xWolf
Hyperion hat geschrieben:Darf man fragen, um was für Daten es da in der Datei geht? Scheint mir ja eine obskure Mischung aus Binär und Textdaten zu sein? Kennst Du das Format näher? Evtl. gibt es ja einen besseren Weg, das zu parsen ...
Hallo,
Vielleicht sind das obskure Daten. Aber ich schleppe diese Daten seit DOS-Zeiten mit.
Es handelt sich tatsaechlich um bits und bytes.
Ein Datensatz hat die Laenge von 370 bytes. Feld1 hat 74 Bytes und Feld2 die restlichen 296 Bytes. Diese lese ich ein und stelle sie in textform dar. das ist alles.
Da es frueher nur 255 (256

) ASCII-Zeichen gab und somit ein ASCII-Zeichen = 1 Byte = 8bit war/ist, gab es da kein Problem. Jetzt mit dem unicode, der 2 Bytes zu einem Zeichen vereint und darstellt habe ich nun ein Problem mit dem zaehlen der Bytes. Da die Funktion:
mir nur die Anzahl der darstellbaren Zeichen und nicht die Anzahl in Bytes zurueck liefert, habe ich ein Problem.
Ich brauche eine Funktion, die mir die Laenge in Bytes gibt.
Kennst Du da was?
Wolf
Verfasst: Dienstag 9. Dezember 2008, 12:57
von Leonidas
In einen Bytestring dekodieren und darauf dann die Anzahl der Bytes zaehlen? Unicode verschmilzt ja bei Bedarf mehrere Bytes zu einem Codepoint und das ist auch gut so, denn normalerweise stellt man darin ja Texte dar und die bestehen aus Zeichen und nicht aus Bytes.
Verfasst: Dienstag 9. Dezember 2008, 13:13
von xWolf
Leonidas hat geschrieben:In einen Bytestring dekodieren und darauf dann die Anzahl der Bytes zaehlen? Unicode verschmilzt ja bei Bedarf mehrere Bytes zu einem Codepoint und das ist auch gut so, denn normalerweise stellt man darin ja Texte dar und die bestehen aus Zeichen und nicht aus Bytes.
Richtig. Das ist ja was ich sagte.
Aber stell Dir vor, Du hast eine Datenbank, (nimm mal dBase) und diese Datenbank besteht aus Datensaetzen und Datenfeldern. Und auch da kann ich ja den unicode benutzen. Nur muss ich, wenn ich die Daten in die Datenbank schreibe auf das Byte genau den Datensatz aus den Informationen der Datenfelder zusammensetzen.
Also muss ich zaehlen, unabhaengig ob es nun unicode ist oder nicht. Die Daten auf der Festplatte bestehen nun mal nur aus Bytes.
Gibt es denn irgendeine Moeglichkeit die tatsaechliche Groesse einer Variablen in Bytes zu bestimmen?
Danke
Wolf
Verfasst: Dienstag 9. Dezember 2008, 15:45
von Leonidas
xWolf hat geschrieben:Gibt es denn irgendeine Moeglichkeit die tatsaechliche Groesse einer Variablen in Bytes zu bestimmen?
Die tatsächliche Größe eines Objektes ist in Python nicht abrufbar. So ist u"abc" nicht zwingend gleich groß wie u"abc", denn es gibt sowohl UCS-2 als auch UCS-4 Varianten von Python die je nach Kompilationseinstellungen Strings im Speicher unterschiedlich darstellen.
Verfasst: Mittwoch 10. Dezember 2008, 04:34
von xWolf
Leonidas hat geschrieben:
Die tatsächliche Größe eines Objektes ist in Python nicht abrufbar. So ist u"abc" nicht zwingend gleich groß wie u"abc", denn es gibt sowohl UCS-2 als auch UCS-4 Varianten von Python die je nach Kompilationseinstellungen Strings im Speicher unterschiedlich darstellen.
Hallo Leonidas,
Richtig. Das war mein Problem,
Also muessen wir es abrufbar machen.
Ich habe mir eine Funktion geschrieben, die die tatsaechliche Laenge der unicode-Zeichenkette in Anzahl-bytes zurueckgibt.
Und zwar nutze ich die hex() Funktion, die mir einen 8-bit, 16-bit oder wie auch immer langen hexadezimalen Wert eines Zeichens zurueckgibt.
Hier das Script.
Code: Alles auswählen
#!/usr/bin/python
# -*- coding: utf-8 -*-
def byteLen(Text):
# ------------ Variableninitialisierung ---------------
xlen = 0 # .....Laenge der Zeichenkette in bytes
i = 0 #.........Schleifenzaehler
l = len(Text) #.Laenge der Zeichenkette in Zeichen
hl = 0 #........Anzahl der Hexadezimalen Zeichen
quo = 0 #.......Quotient auf Hexa-Laenge durch 2
temp = "" #.....temporaere VAriable
while i < l:
temp = hex(ord(Text[i])) #..Zeichen im Text in Hexa-Wert wandeln
temp = temp[2:] #...........das '0x' abschneiden - gehoert nicht zum Hexa-Wert
hl = len(temp) #............Laenge ermitteln
quo = hl / 2 #..............und durch 2 teilen, ein Hexa-Wert besteht immer aus 2 Zeichen
if (quo*2) < hl: #..........falls fuehrende '0' fehlt, dann
temp = "0"+temp #........hinzufuegen um gerade Anzahl an Zeichen zu erhalten
xlen = xlen + len(temp)/2 # .......und Anzahl zur Gesamtlaenge addieren
i = i + 1 #.................Zaehler eins rauf
return xlen #..................Gesamtlaenge zurueckgeben
# nun testen mit einem Zeichen oberhalb ASCII 255 -------------
Text = u"\u0126" # Unicode hex 0126
print "Text:",Text,"Zeichenlaenge:",len(Text)," Byte-Laenge",byteLen(Text)
Kann man einfach wie oben gezeigt kopieren und ausfuehren. Habe ich auch mit chinesischen Zeichen ausprobiert. Klappt.
Das Script wird einigen Profis vielleicht den Angstschweiss in die Stirn treiben, aber "Entscheidend ist was hinten raus kommt!" - hat schon Helmut Kohl gesagt.
Gruss
Wolf
Verfasst: Mittwoch 10. Dezember 2008, 05:28
von BlackJack
@xWolf: Und in diesem Fall kommt hinten Mist raus, die Funktion ist total nutzlos. Unicode hat keine Länge in Bytes, das macht auch überhaupt keinen Sinn, weil man Unicode nicht speichern kann.
Wenn Du Unicode-Text speichern willst, musst Du es unter Angabe einer Kodierung als Bytes kodieren. Und *davon* kannst Du dann die Länge in Bytes ermitteln.
Wenn Du die Daten schon ewig mit Dir herum schleppst, vermute ich mal, dass Du eine Kodierung verwendest, bei der immer ein Zeichen einem Byte entspricht!?
ASCII hat übrigens nur 7-Bit.
Verfasst: Mittwoch 10. Dezember 2008, 06:37
von xWolf
BlackJack hat geschrieben:@xWolf: Und in diesem Fall kommt hinten Mist raus, die Funktion ist total nutzlos. Unicode hat keine Länge in Bytes, das macht auch überhaupt keinen Sinn, weil man Unicode nicht speichern kann.
Wenn Du Unicode-Text speichern willst, musst Du es unter Angabe einer Kodierung als Bytes kodieren. Und *davon* kannst Du dann die Länge in Bytes ermitteln.
Wenn Du die Daten schon ewig mit Dir herum schleppst, vermute ich mal, dass Du eine Kodierung verwendest, bei der immer ein Zeichen einem Byte entspricht!?
ASCII hat übrigens nur 7-Bit.
Sorry,
Dann hast Du es nicht ausprobiert.
Es kommt genau das heraus, was ich erwarte. Der Hex-Wert 0x0126 entspricht genau 2 Byte. Und das ist es, was ich wissen will. Auch UNICODE hat eine Laenge in Bytes oder wie sollen sonst Daten auf der festplatte oder im RAM abgelegt werden? Auch mit Objektphilosophie und Hochsprachen, bleibt die Technik unten drunter immer noch die selbe. 1Wort = 2Byte/ 1Byte = 8bit!
Und auch wenn der Ascii-Code nur 7bit lang ist, also 0-127, wird trotzdem ein Byte abgespeichert, also binaer 01111111!
Auf der Festplatte stehen halt nur Bytes.
Und tatsaechlich repraesentiert ein Byte im Ascii-Code ein Zeichen. Wenn nun 2 Byte fuer ein Zeichen verwendet werden, ist das verstaendlich, trotzdem ist es nicht nutzlos zu wissen, wie lang eine Zeichenkette in Byte ist. Ich habe das versucht mit dem weiter o.g. Beispiel Datenbank/Datensatz/Datenfeld deutlich zu machen.
Wolf
Verfasst: Mittwoch 10. Dezember 2008, 10:51
von Darii
xWolf hat geschrieben:Es kommt genau das heraus, was ich erwarte. Der Hex-Wert 0x0126 entspricht genau 2 Byte. Und das ist es, was ich wissen will. Auch UNICODE hat eine Laenge in Bytes oder wie sollen sonst Daten auf der festplatte oder im RAM abgelegt werden? Auch mit Objektphilosophie und Hochsprachen, bleibt die Technik unten drunter immer noch die selbe.
Indem man die Unicode-Zeichenkette irgendwie kodiert. Es ist völlig sinnfrei die Größe eines Unicode-String in Byte messen zu wollen, ohne vorher die Kodierung festlegen. Ich kann den String auch als Array von 64bit-Integern speichern, dann wäre jedes Zeichen 8 Byte groß.
Code: Alles auswählen
In [16]: Text = u"\u0126"
In [17]: len(Text.encode("utf-7")), len(Text.encode("utf-16"))
Out[17]: (5, 4)
Verfasst: Mittwoch 10. Dezember 2008, 11:04
von BlackJack
@xWolf: Ich brauche es nicht ausprobieren, das ist ein grundsätzliches Verständnisproblem bei Dir. Unicode hat *keine* Länge in Bytes, weil Unicode nur ein abstraktes Konzept ist. Wenn Du das im RAM oder auf Platte speichern möchtest, musst Du das mit einer konkreten Kodierung tun. Dabei kommt dann eine Folge von Bytes heraus, die eine Länge hat. Das ist dann aber kein Unicode mehr.
Du kannst Unicode-Objekte nicht auf Platte schreiben -- Du musst sie vorher immer in eine Folge von Bytes umwandeln. Wie Unicode-Objekte intern gespeichert werden, hat Dich nicht zu interessieren. Das kann je nach Python-Implementierung, -Version, oder sogar Optionen, die beim Übersetzen des Interpreters angegeben wurden, unterschiedlich sein.
Deine Funktion ist sinnlos, weil sie soweit ich das sehe mit keiner Kodierung übereinstimmt. Gebräucliche Kodierung, die Zeichen mit unterschiedlichen Längen kodiert ist UTF-8:
Code: Alles auswählen
In [224]: byteLen(u'ä')
Out[224]: 1
In [225]: len(u'ä'.encode('utf-8'))
Out[225]: 2
Hier kommt zum Beispiel zum tragen, dass ASCII ein 7-Bit-Code ist, weil UTF-8 nur ASCII-Zeichen als 1 Byte kodiert und das 'ä', obwohl der Unicode-Codepoint als Zahl noch in ein Byte passen würde, in zwei Bytes kodiert wird. Wenn Du in Deinen Daten Umlaute hast, dann sind sie nicht ASCII, weil alle Zeichen mit Bytewerten über 127 eben nicht ASCII sind. Und auch dort muss man, um zu wissen was denn nun zum Beispiel ein 'ä' sein soll, eine Kodierung dazu sagen.
Also noch einmal: Man kann nicht sagen wie lang ein Unicode-Objekt in Bytes ist, ohne das man auch eine konkrete Kodierung dazu sagt. Und um diese Länge zu ermitteln ist es wesentlich einfacher das Unicode-Objekt einfach zu kodieren und dann zu schauen wie lang das Ergebnis davon ist, als so eine überkomplizierte Funktion zu verwenden.
Wenn Du Deine Daten schon so lange mit Dir rumschleppst verwendest Du wahrscheinlich eine Kodierung bei der ein Zeichen einem Byte entspricht, dann kannst Du auch einfach `len()` auf dem Unicode-Objekt verwenden.
Verfasst: Mittwoch 10. Dezember 2008, 12:42
von xWolf
BlackJack hat geschrieben:@xWolf: Ich brauche es nicht ausprobieren, das ist ein grundsätzliches Verständnisproblem bei Dir.....
OK, dann habe ich aber ein naechstes Problem.
Die Daten die ich bearbeiten will, sind bereits durch ein anderes programm gelaufen.
Wie finde ich den heraus wie die codiert sind?
Lade ich die Daten in eine Liste und lasse mir die Daten waehrend des Ladevorgangs auf der konsole anzeigen, werden die Umlaute korrekt dargestellt.
In der Liste nicht.
Oeffne ich die Datei mit codecs.open... werden zwar die Umlaute richtig dargestellt aber die Laenge eines Datenfeldes ist nun unbestimmt, da ja entsprechend der Codierung und der Anzahl der Umlaute pro Datenfeld nun die Groesse variiert und ich schon Zeichen aus dem naechsten Datenfeld in das aktuelle mit einlese.
Die Daten habe ich das letzte mal mit Gambas - dem Basic-Interpreter bearbeitet, bei dem diese Codiererei keine Rolle spielte.
Hmmm.

Verfasst: Mittwoch 10. Dezember 2008, 13:07
von helduel
xWolf hat geschrieben:Wie finde ich den heraus wie die codiert sind?
Lade ich die Daten in eine Liste und lasse mir die Daten waehrend des Ladevorgangs auf der konsole anzeigen, werden die Umlaute korrekt dargestellt.
In der Liste nicht.
Wie sehen die Daten in der Liste denn aus?
Verfasst: Mittwoch 10. Dezember 2008, 20:33
von BlackJack
@xWolf: Wie die Daten kodiert sind, musst Du entweder wissen, oder ausprobieren. Such Dir zum Beispiel Umlaute und schau Dir in den Daten an welche Bytewerte die haben und such dann die dazu passende Kodierung.
In Listen werden die Elemente in ihrer `repr()`-Darstellung angezeigt, damit man sehen kann, was da *wirklich* drin steht. Das bedeutet bei `str` und `unicode`, dass alles ausserhalb von ASCII als Escapesequenz dargestellt wird.