Seite 1 von 1

Encoding Fehler bei Exceltabelle auslesen

Verfasst: Montag 8. Januar 2007, 09:48
von alpha
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]

Re: Encoding Fehler bei Exceltabelle auslesen

Verfasst: Montag 8. Januar 2007, 10:18
von gerold
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
:-)

Verfasst: Montag 8. Januar 2007, 10:22
von 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.

Verfasst: Montag 8. Januar 2007, 13:00
von alpha
Hi Blackjack,

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

Thx
alpha

Verfasst: Montag 8. Januar 2007, 13:07
von 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?

Verfasst: Montag 8. Januar 2007, 13:32
von alpha
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

Re: Encoding Fehler bei Exceltabelle auslesen

Verfasst: Montag 8. Januar 2007, 13:34
von gerold
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
:-)

Verfasst: Montag 8. Januar 2007, 13:51
von alpha
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

Verfasst: Montag 8. Januar 2007, 14:02
von BlackJack
Kannst Du `str()` eventuell durch `unicode()` ersetzen? Excel müsste doch intern mittlerweile auch mit Unicode arbeiten.

Verfasst: Montag 8. Januar 2007, 14:07
von gerold
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
:-)

Verfasst: Montag 8. Januar 2007, 17:33
von alpha
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

Verfasst: Montag 8. Januar 2007, 18:23
von 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.

Verfasst: Montag 8. Januar 2007, 18:25
von gerold
...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
:-)

Verfasst: Montag 8. Januar 2007, 18:46
von gerold
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
:-)

Verfasst: Dienstag 9. Januar 2007, 14:11
von alpha
Danke Leute. Das .Text war wohl die Lösung. So gehts :D

Super Hilfe wie immer.

alpha

Verfasst: Donnerstag 11. Januar 2007, 08:26
von alpha
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

Verfasst: Donnerstag 11. Januar 2007, 10:00
von 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'

Verfasst: Mittwoch 31. Januar 2007, 13:23
von nevyn
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')