19

Python xlrdおよびcsvモジュールを使用してExcelスプレッドシートをCSVに変換しようとしていますが、エンコードの問題でハングアップしています。XlrdはExcelからUnicodeで出力を生成し、CSVモジュールにはUTF-8が必要です。

これはxlrdモジュールとは何の関係もないことをイメージしています。stdoutまたは特定のエンコーディングを必要としない他の出力への出力はすべて正常に機能します。

ワークシートは、に従ってUTF-16-LEとしてエンコードされます。book.encoding

私がしていることの簡略化されたバージョンは次のとおりです。

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)

これにより、次のエラーが発生します。約740行です。

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

値がハングアップしているようですが「516-777316」です。元のExcelシートのテキストは「516-7773167」です(末尾に7が付いています)。

私は文字エンコードがどのように機能するかについて漠然とした感覚しか持っていないことを最初に認めます。したがって、これまでに試したことのほとんど.encode.decodes.cell_value(row,col)

誰かが解決策を提案できれば、私はそれをいただければ幸いです-何が機能していないのか、そしてその理由を説明していただければ、将来これらの問題を自分でより簡単にデバッグできるようになります。

前もって感謝します!

編集:

これまでのコメントありがとうございます。

ユーザーthis_row.append(s.cell(row,col))(s.cell_valueではなくegscell)を使用すると、ドキュメント全体がエラーなしで書き込まれます。

出力は特に望ましいものではありませんが(text:u'516-7773167')、問題のある文字がまだ出力に残っている場合でもエラーを回避します。

これは、結局のところ、課題はxlrdにあるのではないかと思います。

考え?

4

4 に答える 4

26

戻りcell_value値は問題を引き起こしているUnicode文字列であると思います(それtype()を確認するために印刷してください)。その場合、次の1行を変更することで解決できるはずです。

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

に:

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

が複数の異なるタイプを返す場合cell_valueは、Unicode文字列を返す場合にのみエンコードする必要があります。したがって、この行を数行に分割します。

val = s.cell_value(row, col)
if isinstance(val, unicode):
    val = val.encode('utf8')
this_row.append(val)
于 2009-07-27T17:37:03.583 に答える
9

あなたは説明を求めましたが、いくつかの現象はあなたの助けなしでは説明できません。

(A)Excel 97以降で作成されたXLSファイルの文字列は、可能であればUTF16LEでLatin1でエンコードされます。各文字列には、どちらが使用されたかを示すフラグが付いています。以前のExcelは、ユーザーの「コードページ」に従って文字列をエンコードしていました。いずれの場合も、xlrdはUnicodeオブジェクトを生成します。ファイルのエンコードは、XLSファイルがサードパーティのソフトウェアによって作成された場合にのみ重要です。サードパーティのソフトウェアは、コードページを省略しているか、コードページに依存しています。xlrdドキュメントの前にあるUnicodeセクションを参照してください。

(B)原因不明の現象:

このコード:

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

Python 2.5、2.6、および3.1で次のエラーが発生しますTypeError: expected at most 2 arguments, got 3。-これは、csv.writerのドキュメントから予想されるものです。ファイルのようなオブジェクトの後に、(1)何もない(2)方言、または(3)1つ以上のフォーマットパラメータが続くことを想定しています。あなたはそれに方言を与えました、そしてcsv.writerにはエンコーディング引数がないので、スプラットします。どのバージョンのPythonを使用していますか?または、実際に実行したスクリプトをコピーして貼り付けませんでしたか?

(C)トレースバックに関する原因不明の現象と、実際の問題のあるデータは次のとおりです。

"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) 

まず、問題のあるコード行に、簡略化されたスクリプトにはなかったstr()があります。実際に実行したスクリプトをコピーして貼り付けませんでしたか?いずれにせよ、一般的にstrを使用するべきではありません。フロートで完全な精度を得ることができません。csvモジュールに変換させてください。

次に、"""値がハングアップしているようです"516-777316"-元のExcelシートのテキストは"516-7773167"(末尾に7が付いています)" ""- -7がどのように最後から失われるかを想像するのは難しいです。問題のあるデータが何であるかを正確に調べるには、次のようなものを使用します。

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

その%rにより、入力する手間が省けますcell_value=%s ... repr(s.cell_value(row, col))... repr()は、データの明確な表現を生成します。勉強しなさい。これを使って。

どうやって「516-777316」にたどり着きましたか?

第3に、エラーメッセージは、実際にはオフセット5(つまり6番目の文字)にあるUnicode文字u'\xed'について不平を言っています。U + 00EDはラテン語の小さな文字Iであり、「516-7773167」にはそのようなものはまったくありません。

第4に、エラーの場所は移動するターゲットのようです。解決策の1つについてのコメントで、「エラーはbcw.writerowにあります」と述べています。は?

(D)エラーメッセージが表示される理由(str()を使用):str(a_unicode_object)Unicodeオブジェクトをstrオブジェクトに変換しようとし、エンコード情報がない場合はasciiを使用しますが、非ASCIIデータがあるため、スプラットします。オブジェクトはutf8でエンコードされたcsvファイルを生成することですが、簡略化されたスクリプトではutf8についてはどこにも言及されていないことに注意してください。

(E) "" "... s.cell(row、col))(s.cell_value)ドキュメント全体の代わりにegscellがエラーなしで書き込みます。出力は特に望ましくありません(text:u'516-7773167')" ""

これは、csvライターが__str__Cellオブジェクトのメソッドを呼び出しているために発生します。これにより<type>:<repr(value)>、デバッグに役立つ可能性がありますが、csvファイルではそれほど優れていません。

(F)Alex Martelliのソリューションは、うまくいくという点で優れています。ただし、xlrdドキュメントのCellクラスのセクションを読む必要があります。セルのタイプは、テキスト、数値、ブール値、日付、エラー、空白、および空です。日付がある場合は、数値ではなく日付としてフォーマットする必要があるため、isinstance()を使用することはできません(とにかく関数呼び出しのオーバーヘッドは必要ない場合があります)...これがCell.ctype属性Sheet.cell_type()Sheet.row_types()メソッドですのためです。

(G)UTF8はUnicodeではありません。UTF16LEはUnicodeではありません。UTF16はUnicodeではありません...そして個々の文字列がUTF16BOMでそれぞれ2バイトを浪費するという考えは、MSでさえ考えるにはあまりにも馬鹿げています:-)

(H)さらに読む(xlrdドキュメントは別として):

http://www.joelonsoftware.com/articles/Unicode.html
http://www.amk.ca/python/howto/unicode
于 2009-07-28T10:45:53.510 に答える
0

2つの可能性があるようです。1つは、出力ファイルを正しく開いていない可能性があることです。

「csvfileがファイルオブジェクトの場合、違いが生じるプラットフォームでは「b」フラグを付けて開く必要があります。」(http://docs.python.org/library/csv.html#module-csv

それが問題ではない場合は、codecs.EncodedFile(file、input [、output [、errors]])をラッパーとして使用して.csvを出力することもできます。

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

これにより、着信UTF16からUTF8へのファイルオブジェクトフィルターを設定できます。どちらも技術的には「ユニコード」ですが、エンコードの方法は大きく異なります。

このようなもの:

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

私が問題を正しく理解し、ファイルへの書き込み時にエラーがスローされると仮定すると、問題が解決する可能性があります。

于 2009-07-27T16:26:45.333 に答える
0

2つの問題があるようです。

そのセルには何かがおかしくなっています。「7」はASCII範囲内にあるため、「x37」としてエンコードする必要があります。

asciiさらに重要なのは、コーデックを使用できないことを示すエラーメッセージが表示されているという事実は、 Unicodeへのエンコードに問題0xedがあることを示しています。ASCIIで表現できない値をエンコードしようとしていると考えられます。 、しかしあなたはそれをユニコードで表現しようとしていると言いました。

問題の原因となっている特定の行を特定するのに十分な知識がありません。質問を編集して、エラーメッセージの原因となっている行を教えていただければ、もう少しお手伝いできるかもしれません(またはのどちらかだと思いますが、よろしくお願いthis_row.append(s.cell_value(row,col))bcw.writerow(this_row)ます) 。あなたが確認します)。

于 2009-07-27T16:27:06.923 に答える