Frage

Ich versuche, eine Excel-Tabelle in CSV zu übersetzen mit der Python xlrd und csv-Module, aber ich bin immer auf kodieren Fragen aufgehängt. Xlrd erzeugt eine Ausgabe von Excel in Unicode, und das CSV-Modul benötigt UTF-8.

I Imaging, dass dies nichts mit dem xlrd Modul zu tun. Alles in Ordnung outputing an stdout oder anderen Ausgängen arbeitet, die keine spezifische Codierung erfordern

Das Arbeitsblatt wird codiert als UTF-16-LE, gemäß book.encoding

Die vereinfachte Version von dem, was ich tue, ist:

from xlrd import *
import csv
b = open_workbook('file.xls')
s = b.sheet_by_name('Export')
bc = open('file.csv','w')
bcw = csv.writer(bc,csv.excel,b.encoding)
for row in range(s.nrows):
    this_row = []
    for col in range(s.ncols):
        this_row.append(s.cell_value(row,col))
    bcw.writerow(this_row)

Dies erzeugt die folgenden Fehler, etwa 740 Zeilen in:

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

Der Wert wird scheint auf immer aufgehängt wird auf ist „516-777316“ - der Text in der ursprünglichen Excel-Tabelle ist „516-7773167“ (mit einem 7 am Ende)

Ich werde die erste zugeben, dass ich nur eine vage Vorstellung davon, wie Zeichenkodierung funktioniert, so dass die meisten von dem, was ich habe versucht, so weit sind verschiedene Fummelei Permutationen von .encode und .decode auf dem s.cell_value(row,col)

Wenn jemand eine Lösung vorschlagen könnte, würde ich es zu schätzen wissen -. Noch besser, wenn Sie eine Erklärung liefern könnten, was nicht funktioniert und warum, damit ich leichter diese Probleme selbst in der Zukunft debuggen kann

Vielen Dank im Voraus!

EDIT:

Danke für die Kommentare so weit.

Wenn ich Benutzer this_row.append(s.cell(row,col)) (z s.cell statt s.cell_value) das gesamte Dokument schreibt ohne Fehler.

Der Ausgang ist nicht besonders wünschenswert (text:u'516-7773167'), aber es vermeidet den Fehler, obwohl die säumigen Zeichen nach wie vor in der Ausgabe sind.

Das macht ich denke, dass die Herausforderung in xlrd schließlich sein könnte.

Die Gedanken?

War es hilfreich?

Lösung

Ich erwarte von dem cell_value Rückgabewert ist die Unicode-Zeichenfolge, die Ihnen Probleme (bitte in Druck seine type() bestätigen, dass) sind zu geben, in diesem Fall sollten Sie sie lösen können, indem diese eine Zeile zu ändern:

this_row.append(s.cell_value(row,col))

zu:

this_row.append(s.cell_value(row,col).encode('utf8'))

Wenn cell_value mehr verschiedenen Typen zurückgibt, dann müssen Sie zu kodieren, wenn und nur wenn es einen Unicode-String zurückkehren; so dass Sie diese Zeile in ein paar Zeilen aufgeteilt würden:

val = s.cell_value(row, col)
if isinstance(val, unicode):
    val = val.encode('utf8')
this_row.append(val)

Andere Tipps

Sie fragte nach Erklärungen, aber einige der Phänomene sind unerklärlich ohne Ihre Hilfe.

(A) Strings in XLS-Dateien von Excel erstellt 97 weiter in Latin1 codieren, wenn möglich, sonst in Utf16LE. Jeder String trägt eine Fahne mitteilt, welche verwendet wurde. Frühere Zeichnet kodierten Strings nach dem „Codepage“ des Benutzers. In jedem Fall xlrd produziert Unicode-Objekte . Die Datei-Codierung ist von Interesse, nur dann, wenn die XLS-Datei wird von 3rd-Party-Software erstellt wurde, die entweder die Codepage oder Lügen über sie auslässt. Siehe den Unicode-Abschnitt auf der Vorderseite der xlrd docs.

(B) unerklärliches Phänomen:

Mit diesem Code:

bcw = csv.writer(bc,csv.excel,b.encoding)

verursacht die folgenden Fehler mit Python 2.5, 2.6 und 3.1: TypeError: expected at most 2 arguments, got 3 - das über das, was ich die Dokumentationen zu csv.writer gegeben erwarten würde; es wird erwartet eine filelike Aufgabe durch entweder (1) nichts (2) einen Dialekt oder (3) eine oder mehr Formatierungsparameter verfolgt wird. Sie gab ihm einen Dialekt, und csv.writer hat kein Argument kodiert, so Splat. Welche Version von Python verwenden Sie? Oder haben Sie nicht kopieren / einfügen um das Skript, dass Sie tatsächlich lief?

(C) Unerklärliche Phänomene um Traceback und was die tatsächlichen anstößigen Daten waren:

"the_script.py", line 40, in <module>
this_row.append(str(s.cell_value(row,col)))
UnicodeEncodeError: 'ascii' codec can't encode character u'\xed' in position 5: ordinal not in range(128) 

ERSTENS, gibt es eine str () in der beanstandeten Codezeile, die nicht im vereinfachten Skript war - haben Sie nicht kopieren / einfügen um das Skript, dass Sie tatsächlich ran? Auf jeden Fall sollten Sie nicht str im Allgemeinen verwenden - Sie werden nicht die volle Präzision auf dem Schwimmer erhalten; lassen Sie einfach die CSV-Modul konvertiert sie.

ZWEITENS, sagen Sie „“ „Der Wert scheint, ist aufgehängt zu werden Einsteigen ist‚516-777316‘- der Text in der ursprünglichen Excel-Tabelle ist‚516-7773167‘(mit einem 7 am Ende)“ „“ --- es ist schwer vorstellbar, wie die 7 über das Ende verloren geht. Ich würde so etwas wie diese benutze, um genau herauszufinden, was die problematischen Daten waren:

try:
    str_value = str(s.cell_value(row, col))
except:
    print "row=%d col=%d cell_value=%r" % (row, col, s.cell_value(row, col))
    raise

Das% r erspart Sie Tipp cell_value=%s ... repr(s.cell_value(row, col)) ... die repr () erzeugt eine eindeutige Darstellung Ihrer Daten. Lern es. Verwenden Sie es.

Wie haben Sie kommen am "516-777316"?

Drittens wird die Fehlermeldung tatsächlich beschwert über ein Unicode-Zeichen u ‚\ festen‘ bei Offset 5 (das heißt das sechste Zeichen). U + 00ED ist LATIN Kleiner i mit Akut, und es gibt nichts, wie das überhaupt in „516-7773167“

VIERTENS scheint die Fehlerstelle ein sich bewegendes Ziel zu sein - sagte Sie in einem Kommentar zu einer der Lösungen: „Der Fehler auf bcw.writerow ist.“ Huh?

(D) Warum Sie diese Fehlermeldung bekommen (mit str ()): str(a_unicode_object) Versuche, das Unicode-Objekt zu einem str Objekt und in Ermangelung einer Codierung Informationen Verwendungen ascii zu konvertieren, aber Sie haben nicht-ASCII-Daten, so zu. Beachten Sie, dass Ihr Ziel ist, eine CSV-Datei in UTF-8 codiert werden, aber Ihr vereinfachtes Skript nicht utf8 überall erwähnen.

(E) ""“... s.cell (Zeile, Spalte)) (egscell statt s.cell_value) das gesamte Dokument schreibt ohne Fehler Der Ausgang ist nicht besonders wünschenswert (Text:. U'516-7773167' ) "" "

Das geschieht, weil der csv Schriftsteller ist die __str__ Methode der Cell-Objekt aufrufen, und dies erzeugt <type>:<repr(value)>, die für die Fehlersuche nützlich sein können, aber wie Sie sagen, nicht so groß in der CSV-Datei.

(F) Alex Martelli Lösung ist groß, dass es bekommen Sie gehen. Zelltypen sind Text, Zahl, Boolean, Datum, Fehler, blank und leer: Allerdings sollten Sie den Abschnitt auf der Zellklasse in dem xlrd docs lesen. Wenn Sie Termine haben, werden Sie sie als Datum oder Zahlen zu formatieren, so dass Sie nicht isinstance verwenden können () (und Sie können nicht den Funktionsaufruf wollen Overhead sowieso) ... das ist, was die Cell.ctype Attribut und Sheet.cell_type() und Sheet.row_types() Methoden sind für.

(G) UTF8 ist nicht Unicode. Utf16LE ist nicht Unicode. UTF16 ist nicht Unicode ... und die Idee, dass die einzelnen Strings 2 Bytes jeweils auf einer UTF16 BOM verschwenden würden sogar MS zu erwägen auch unsinnig ist: -)

(H) Literatur (abgesehen von der xlrd docs):

http://www.joelonsoftware.com/articles/Unicode.html
http://www.amk.ca/python/howto/unicode

Sieht aus wie Sie haben zwei Probleme.

Es ist etwas in dieser Zelle vermasselt -. ‚7‘ sollte als u'x37' codiert werden denke ich, da es im ASCII-Bereich ist

Noch wichtiger ist jedoch die Tatsache, dass Sie eine Fehlermeldung, wenn es darum festlegt, dass der ascii Codec schlägt mit Codierung etwas falsch sein kann in Unicode nicht verwendet - es denkt, dass Sie versuchen, einen Wert 0xed das kann zu kodieren‘ t in ASCII dargestellt werden, aber Sie sagen Sie versuchen, es in Unicode darzustellen.

ich nicht klug genug bin, um herauszufinden, was bestimmte Linie ist das Problem verursacht - wenn Sie Ihre Frage bearbeiten, mir zu sagen, welche Zeile der die Fehlermeldung verursacht ich in der Lage vielleicht ein bisschen mehr zu helfen (Ich denke, es entweder this_row.append(s.cell_value(row,col)) ist oder bcw.writerow(this_row), würde aber schätzen Sie bestätigt).

Es erscheinen zwei Möglichkeiten zu sein. Eine davon ist, dass Sie vielleicht nicht die Ausgabedatei korrekt geöffnet:

„Wenn csvfile ein Dateiobjekt ist, muss es mit dem‚b‘Flag auf Plattformen geöffnet werden, wenn das einen Unterschied macht.“ ( http://docs.python.org/library/csv.html#module -csv )

Wenn das nicht das Problem ist, dann für Sie eine weitere Option ist codecs.EncodedFile zu verwenden (Datei, Eingang [, Ausgang [Fehler]]) als Wrapper zur Ausgabe Ihrer CSV:

http://docs.python.org/library/codecs.html # Modul-Codecs

Damit können Sie die Datei Objektfilter von eingehenden UTF16 auf UTF8 haben. Während beide technisch „Unicode“ sind, ist die Art und Weise sie kodieren, sehr unterschiedlich.

So etwas wie folgt aus:

rbc = open('file.csv','w')
bc = codecs.EncodedFile(rbc, "UTF16", "UTF8")
bcw = csv.writer(bc,csv.excel)

kann das Problem für Sie lösen, vorausgesetzt, ich das Problem richtig verstanden, und unter der Annahme, dass der Fehler ausgelöst wird, wenn in die Datei geschrieben werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top