Encoding Fehler bei Exceltabelle auslesen

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
alpha
User
Beiträge: 195
Registriert: Freitag 23. Mai 2003, 23:24
Wohnort: Ulm

Hallo Pythonfreunde,

ich bekomme in folgender Zeile:

Code: Alles auswählen

    wert = str(MyWorkSheet.Cells(1,spalte)).encode("utf-8")
diesen Fehler:

Traceback (most recent call last):
File "N:\scripts\Python\excellesen.py", line 32, in <module>
wert = str(MyWorkSheet.Cells(1,spalte)).encode("utf-8")
File "C:\programme\Python25\Lib\site-packages\win32com\client\dynamic.py", lin
e 187, in __str__
return str(self.__call__())
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 18:
ordinal not in range(128)

Ich hab jetzt schon ewig mit den Encodings rumexperimentiert aber komme zu keinem brauhcbaren Ergebnis. Könnt ihr mir weiterhelfen?

Grüße
alpha[/code]
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

alpha hat geschrieben:Könnt ihr mir weiterhelfen?
Hi alpha!

http://www.python-forum.de/topic-5095.html

Ich glaube nicht, dass du nach dieser Lektüre noch Fragen hast. Wenn doch -- einfach melden!

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

`str()` wandelt ein Objekt in eine Zeichenkette. Bei einer Unicode-Zeichenkette als Argument muss diese irgendwie kodiert werden. Da wird als kleinster gemeinsamer Nenner ASCII genommen, was wie man sieht fehlschlägt, wenn die Unicode-Zeichenkette Zeichen ausserhalb von ASCII enthält.

Danach versuchst Du ein `encode()`, was aber für Zeichensatz-Kodierungen nur auf Unicode-Zeichenketten Sinn macht.
alpha
User
Beiträge: 195
Registriert: Freitag 23. Mai 2003, 23:24
Wohnort: Ulm

Hi Blackjack,

aber wie kodiere ich dann ein Objekt? Encode geht ja nur auf strings.

Thx
alpha
BlackJack

Ich dachte das wäre schon eine Unicode-Zeichenkette!? Was ist das denn für ein Objekt und was kommt beim Aufruf der `str()`-Funktion mit diesem Objekt als Argument als Ergebnis heraus?
alpha
User
Beiträge: 195
Registriert: Freitag 23. Mai 2003, 23:24
Wohnort: Ulm

Hi Blackjack,

hier der Programmausschnitt

Code: Alles auswählen

MyApp = win32com.client.Dispatch("Excel.Application")
MyWorkbook = MyApp.Workbooks.Open("c:/temp/Legende_HMI_CANtrol.xls")
MyWorkSheet = MyWorkbook.Worksheets("Legende_HMI_CANtrol")

tabelle = []
spalte = 0
while True:
    spalte += 1
    print spalte
    #wert = ConvertText(str(MyWorkSheet.Cells(1,spalte)))
    print type(MyWorkSheet.Cells(1,spalte))
    wert = str(MyWorkSheet.Cells(1,spalte)).encode("iso-8859-1")
    print wert
    if wert is None or spalte > 255:
        break
    tabelle.append(MyWorkSheet.Cells(1,spalte))
print tabelle[9]
und hier die Ausgabe:


N:\scripts\Python>excellesen.py
1
<type 'instance'>
OPC-Item
2
<type 'instance'>
Einheit
3
<type 'instance'>
Beschreibung
deutsch / englisch
4
<type 'instance'>
Bemerkungen deutsch / englisch
5
<type 'instance'>
Beschreibung
deutsch
6
<type 'instance'>
Bemerkungen deutsch
7
<type 'instance'>
Beschreibung
englisch
8
<type 'instance'>
Bemerkungen englisch
9
<type 'instance'>
Traceback (most recent call last):
File "N:\scripts\Python\excellesen.py", line 33, in <module>
wert = str(MyWorkSheet.Cells(1,spalte)).encode("iso-8859-1")
File "C:\programme\Python25\Lib\site-packages\win32com\client\dynamic.py", lin
e 187, in __str__
return str(self.__call__())
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 18:
ordinal not in range(128)


Bei "Bemerkung französisch" steigt er wegen dem ö aus.

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

alpha hat geschrieben:ich bekomme in folgender Zeile:

Code: Alles auswählen

wert = str(MyWorkSheet.Cells(1,spalte)).encode("utf-8")
diesen Fehler:

Traceback (most recent call last):
File "N:\scripts\Python\excellesen.py", line 32, in <module>
wert = str(MyWorkSheet.Cells(1,spalte)).encode("utf-8")
File "C:\programme\Python25\Lib\site-packages\win32com\client\dynamic.py", lin
e 187, in __str__
return str(self.__call__())
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 18:
ordinal not in range(128)
Hi alpha!

Um einen Text in eine besondere Codierung (z.B. utf-8) umzuwandeln, musst du zuerst herausfinden, in welcher Codierung der Quelltext vorhanden ist, oder ob dieser evt. bereits in Unicode vorliegt.

Ob Unicode oder nicht, sagt dir ``type``:

Code: Alles auswählen

print type(MyWorkSheet.Cells(1,spalte))
Wenn der Text im Unicode vorliegt, dann kannst du mit ``encode("utf-8")`` nach UTF-8 umwandeln.

Liegt der Text aber nicht im Unicode vor, musst du herausfinden, in welchem Coding dein Text vorliegt.

Unter einem deutschsprachigen Windows gibt es nicht viele mögliche Encodings. cp1252, iso-8859-1, iso-8859-15, mbcs und cp850. Die Reihenfolge entspricht in etwa der Wahrscheinlichkeit, da ein Encoding nicht sicher festgestellt, sondern nur nach Wahrscheinlichkeit erraten werden kann.

Am besten, du nimmst dir dafür eine Python-Shell zur Hand, die mit Umlauten umgehen kann. Ich verwende dafür gerne die PyShell, die beim wxPython-Demo mit dabei ist. Du kannst aber auch Idle verwenden.
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 18:
ordinal not in range(128)
Dann lass uns mal herausfinden, mit welchem Buchstaben es ein Problem gibt.

In Idle::

Code: Alles auswählen

>>> print "\xf6"
ö
>>>

Es handelt sich also um das kleine "ö".

Ich setzte das mal ein bischen fort:

Code: Alles auswählen

>>> u"ö"
u'\xf6'
>>> u"ö".encode("cp1252")
'\xf6'
>>> u"ö".encode("utf-8")
'\xc3\xb6'
>>>
Der wahrscheinlichste Fall ist, vorausgesetzt, dass der Typ den du beim Prüfen mit ``type`` zurück bekommst nicht ``<type 'unicode'>`` ist, dass dein Text im Coding "cp1252" an Python übergeben wurde. Vielleicht auch in einem der anderen Encodings. Das musst du dann ausprobieren.

Die Umwandlung passiert, wie in http://www.python-forum.de/topic-5095.html aufgezeigt, über Unicode.

Code: Alles auswählen

text_cp1252 = MyWorkSheet.Cells(1,spalte)
text_unicode = text_cp1252.decode("cp1252")
text_utf8 = text_unicode.encode("utf-8")

# oder kurz
text_utf8 = MyWorkSheet.Cells(1,spalte).decode("cp1252").encode("utf-8")
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
alpha
User
Beiträge: 195
Registriert: Freitag 23. Mai 2003, 23:24
Wohnort: Ulm

Hallo Gerold,

wie oben beschrieben ist der Typ leider "instance" also irgendein Excel Objekt (meiner bescheidenen Meinung nach). Daher muss ich bevor ich .decode oder .encode verwende eine Stringwandlung machen. Kann ich eine Stringwandlung machen bei der immer ein Unicodestring herauskommt? Das sollte doch helfen. Dann müsste ich danach nur noch eine .encode machen und es sollte gehen, oder?

alpha
BlackJack

Kannst Du `str()` eventuell durch `unicode()` ersetzen? Excel müsste doch intern mittlerweile auch mit Unicode arbeiten.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

alpha hat geschrieben:wie oben beschrieben ist der Typ leider "instance"
Hi alpha!

Code: Alles auswählen

# dann gehts entweder so
text_unicode = unicode(MyWorkSheet.Cells(1,spalte))
text_utf8 = text_unicode.encode("utf-8")

# oder so
text_unicode = unicode(MyWorkSheet.Cells(1,spalte), "cp1252")
text_utf8 = text_unicode.encode("utf-8")
``unicode()`` ist so etwas wie ``str()``. Kann also als Ersatz für ``"ööö".decode()`` verwendet werden.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
alpha
User
Beiträge: 195
Registriert: Freitag 23. Mai 2003, 23:24
Wohnort: Ulm

Hi Gerold,

danke für Deine Antworten. Leider funktionieren beide Varianten nciht.

Bei der ersten Variante krachts bei der Spalte mit dem ö:

UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 18:
ordinal not in range(128)

Bei der 2. Variante krachts gleich weil der Rückgabetyp 'type instance' ist und die Wandlung nur für Strings oder Unicodeobjekte funktioniert.

Irgendwie komm ich nicht weiter :?

alpha
BlackJack

Dann musst Du entweder einen Weg finden von so einem Zellenobjekt den Inhalt als Unicode zu bekommen, so eine Zelle hat sicher Attribute und Methoden, oder eben herausfinden in welcher Kodierung die Zeichenkette vorliegt, die man mit `str()` erhält, um sie umkodieren zu können.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

...hier ist die Lösung:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

import os
import win32com.client


filename = os.path.abspath("aaa.xls")

excel_app = win32com.client.dynamic.Dispatch("Excel.Application")
excel_workbook = excel_app.Workbooks.Open(filename)
excel_sheet = excel_workbook.Worksheets("bbb")

print repr(excel_sheet.Cells(1, 1))
print repr(excel_sheet.Range("A1"))

print "Formula:", repr(excel_sheet.Cells(1, 1).Formula)
print "Text:", repr(excel_sheet.Range("A1").Text)
print "Value:", repr(excel_sheet.Range("A1").Value)

utf8_string = excel_sheet.Range("A1").Text.encode("utf-8")
print "UTF-8:", repr(utf8_string)

excel_workbook.Close()
excel_app.Quit()

del excel_sheet
del excel_workbook
del excel_app
Ausgabe, wenn in "A1" der Text "öäüß" steht:

Code: Alles auswählen

<COMObject <unknown>>
<COMObject Range>
Formula: u'\xf6\xe4\xfc\xdf'
Text: u'\xf6\xe4\xfc\xdf'
Value: u'\xf6\xe4\xfc\xdf'
UTF-8: '\xc3\xb6\xc3\xa4\xc3\xbc\xc3\x9f'
Ausgabe, wenn in "A2" der Wert 1.12345 steht, und in "A1" die Formel "=A2":

Code: Alles auswählen

<COMObject <unknown>>
<COMObject Range>
Formula: u'=A2'
Text: u'1,2345'
Value: 1.2344999999999999
UTF-8: '1,2345'
Und hier die Ausgabe, wenn in "A1" direkt der Wert 1.2345 steht:

Code: Alles auswählen

<COMObject <unknown>>
<COMObject Range>
Formula: u'1.2345'
Text: u'1,2345'
Value: 1.2344999999999999
UTF-8: '1,2345'
Du bekommst also Unicode-Strings zurück, und solltes aufpassen, was du dir zurück geben lässt. Formula, Text oder Value liefern je nach art der Zelle etwas komplett anderes zurück. "Text" ist besonders irritierend, da damit bei Zahlen je nach Ländereinstellung etwas anderes zurück gegeben wird.

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:

Falls du immer UTF-8 brauchst, auch wenn eine Zahl in der Zelle steht:

Code: Alles auswählen

retval = excel_sheet.Range("A1").Value
print "Original:", repr(retval)
retval = unicode(retval)
utf8_string = retval.encode("utf-8")
print "Unicode:", repr(retval)
print "UTF8:", repr(utf8_string)
Ausgabe:

Code: Alles auswählen

Original: 1.2344999999999999
Unicode: u'1.2345'
UTF8: '1.2345'
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
alpha
User
Beiträge: 195
Registriert: Freitag 23. Mai 2003, 23:24
Wohnort: Ulm

Danke Leute. Das .Text war wohl die Lösung. So gehts :D

Super Hilfe wie immer.

alpha
alpha
User
Beiträge: 195
Registriert: Freitag 23. Mai 2003, 23:24
Wohnort: Ulm

Hallo nochmal,

jetzt hab ich leider noch ein weiteres mir unerklärliches Problem.
erst mal mein kleines Progrämmchen:

Code: Alles auswählen

# -*- coding: iso-8859-1 -*-

import win32com.client
import string

MyApp = win32com.client.Dispatch("Excel.Application")
MyWorkbook = MyApp.Workbooks.Open("c:/temp/Legende_HMI_CANtrol.xls")
MyWorkSheet = MyWorkbook.Worksheets("Legende_HMI_CANtrol")

tabelle = []
spalte = 0
while True:
    spalte += 1
    print spalte
    wert = MyWorkSheet.Cells(1,spalte).Text
    print type(wert)
    print wert
    
  
    if wert == "":
        break
    tabelle.append(wert)
   
print tabelle
Und hier die Ausgabe:

Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

N:\scripts\Python>excellesen.py
1
<type 'unicode'>
OPC-Item
2
<type 'unicode'>
Einheit
3
<type 'unicode'>
Beschreibung
deutsch / englisch
4
<type 'unicode'>
Bemerkungen deutsch / englisch
5
<type 'unicode'>
Beschreibung
deutsch
6
<type 'unicode'>
Bemerkungen deutsch
7
<type 'unicode'>
Beschreibung
englisch
8
<type 'unicode'>
Bemerkungen englisch
9
<type 'unicode'>
Beschreibung
französisch
10
<type 'unicode'>
Bemerkungen französisch
11
<type 'unicode'>
Beschreibung
spanisch
12
<type 'unicode'>
Bemerkungen spanisch
13
<type 'unicode'>
Beschreibung
xxxxx
14
<type 'unicode'>
Bemerkungen xxxxx
15
<type 'unicode'>

[u'OPC-Item', u'Einheit', u'Beschreibung\ndeutsch / englisch', u'Bemerkungen deu
tsch / englisch', u'Beschreibung\ndeutsch', u'Bemerkungen deutsch', u'Beschreibu
ng\nenglisch', u'Bemerkungen englisch', u'Beschreibung\nfranz\xf6sisch', u'Bemer
kungen franz\xf6sisch', u'Beschreibung\nspanisch', u'Bemerkungen spanisch', u'Be
schreibung\nxxxxx', u'Bemerkungen xxxxx']

N:\scripts\Python>

Und nun meine Frage:
"Bemerkungen französisch" wird im Unicode String richtig gespeichert und ausgegeben, wieso wird es dann in der Liste "tabelle" falsch gespeichert? Ich hab keine Erklärung dafür. Hab schon die ganzen encodings vorher darüber laufen lassen, ohne Erfolg. Hat jemand von euch ne Idee?

Danke fürs helfen.

alpha
BlackJack

alpha hat geschrieben:[u'OPC-Item', u'Einheit', u'Beschreibung\ndeutsch / englisch', u'Bemerkungen deu
tsch / englisch', u'Beschreibung\ndeutsch', u'Bemerkungen deutsch', u'Beschreibu
ng\nenglisch', u'Bemerkungen englisch', u'Beschreibung\nfranz\xf6sisch', u'Bemer
kungen franz\xf6sisch', u'Beschreibung\nspanisch', u'Bemerkungen spanisch', u'Be
schreibung\nxxxxx', u'Bemerkungen xxxxx']

N:\scripts\Python>

Und nun meine Frage:
"Bemerkungen französisch" wird im Unicode String richtig gespeichert und ausgegeben, wieso wird es dann in der Liste "tabelle" falsch gespeichert?
Der wird in der Liste nicht "falsch" gespeichert. Er wird dort nur so ausgegeben, dass man ihn bei (fast) jeder Kodierung lesen kann, indem alles, was nicht ASCII ist, als Escapesequenz dargestellt wird.

Code: Alles auswählen

In [2]: print u'franz\xf6sisch'
französisch

In [3]: print repr(u'franz\xf6sisch')
u'franz\xf6sisch'
nevyn
User
Beiträge: 1
Registriert: Mittwoch 27. September 2006, 10:15
Wohnort: Hannover

Der Code hakt:

Code: Alles auswählen

retval = excel_sheet.Range("A1").Value
print "Original:", repr(retval)
retval = unicode(retval)
utf8_string = retval.encode("utf-8")
print "Unicode:", repr(retval)
print "UTF8:", repr(utf8_string)
Sollten Sonderzeichen wie Umlaute in retval sein, läuft es auf einen Fehler hinaus. unicode benötigt einen encoding-Schlüssel. Z.B.

Code: Alles auswählen

retval = unicode(retval,'cp1252')
Antworten