geloest - unicode problem

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
Benutzeravatar
xWolf
User
Beiträge: 62
Registriert: Sonntag 2. November 2008, 01:21
Wohnort: China

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
Zuletzt geändert von xWolf am Mittwoch 10. Dezember 2008, 04:01, insgesamt 1-mal geändert.
Lonestar
User
Beiträge: 147
Registriert: Samstag 9. August 2008, 08:31

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
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
xWolf
User
Beiträge: 62
Registriert: Sonntag 2. November 2008, 01:21
Wohnort: China

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
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Als zweiten Parameter zu ``unicode()`` oder als 1. Parameter zu ``"string".decode()``.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Over du verwendest codecs.open
Benutzeravatar
xWolf
User
Beiträge: 62
Registriert: Sonntag 2. November 2008, 01:21
Wohnort: China

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
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

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 ...
Benutzeravatar
xWolf
User
Beiträge: 62
Registriert: Sonntag 2. November 2008, 01:21
Wohnort: China

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:

Code: Alles auswählen

 Anzahl = len(Text)
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
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
xWolf
User
Beiträge: 62
Registriert: Sonntag 2. November 2008, 01:21
Wohnort: China

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
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
xWolf
User
Beiträge: 62
Registriert: Sonntag 2. November 2008, 01:21
Wohnort: China

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. :D

Gruss

Wolf
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.
Benutzeravatar
xWolf
User
Beiträge: 62
Registriert: Sonntag 2. November 2008, 01:21
Wohnort: China

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
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

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)

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.
Benutzeravatar
xWolf
User
Beiträge: 62
Registriert: Sonntag 2. November 2008, 01:21
Wohnort: China

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. :(
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

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?
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.
Antworten