質問

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

これは xlrd モジュールとは何の関係もないように思えます。標準出力または特定のエンコーディングを必要としない他の出力への出力では、すべてが正常に機能します。

によると、ワークシートは 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 の代わりに s.cell)、ドキュメント全体がエラーなしで書き込まれます。

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

このことから、挑戦は結局のところ xlrd にあるのではないかと考えさせられます。

考えは?

役に立ちましたか?

解決

私は期待しています 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)

他のヒント

あなたは説明を求めましたが、現象の中にはあなたの助けがなければ説明できないものもあります。

(A) Excel 97 以降で作成された XLS ファイル内の文字列は、可能であれば Latin1 でエンコードされ、それ以外の場合は UTF16LE でエンコードされます。各文字列には、どれが使用されたかを示すフラグが付いています。以前の 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 を使用すべきではありません。float では完全な精度が得られません。csv モジュールに変換させるだけです。

2 番目に、「「値が引っかかっているようです」は「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」にたどり着いたのでしょうか?

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

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

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

(エ)「」「…」s.cell(row,col)) (例:代わりに s.cell s.cell_value) ドキュメント全体がエラーなく書き込まれます。出力は特に望ましいものではありません (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ではありません...そして、UTF16 BOM で個々の文字列がそれぞれ 2 バイトを無駄にするという考えは、MS ですら考えるには非常識すぎます :-)

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

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

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

そのセルには何か問題があります。「7」は ASCII 範囲内にあるため、u'x37' としてエンコードされるべきだと思います。

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

私は問題の原因となっている特定の行を特定できるほど頭が良くありません。質問を編集して、どの行がそのエラー メッセージの原因となっているのかを教えていただければ、もう少し解決できるかもしれません(どちらかだと思います) this_row.append(s.cell_value(row,col)) または bcw.writerow(this_row), 、ご確認いただければ幸いです)。

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 にフィルターできるようになります。どちらも技術的には「Unicode」ですが、エンコード方法は大きく異なります。

このようなもの:

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

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top