2009-07-27 17 views
18

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

このイメージングは​​xlrdモジュールとは関係がありません。すべては、stdoutや特定のエンコーディングを必要としないその他の出力に出力されます。

ワークシートはbook.encoding

が何であるかを私がやっているの簡易版によると、UTF-16-LEとしてエンコードされます。

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で終わりに)

私は私がこれまで試したものの大部分はs.cell_value(row,col)

.encode.decodeの様々な手探りの順列があるので、私は、文字エンコーディングがどのように動作するかの漠然としか意味を持っていることを認めざるを最初になりますもし誰かが解決策を提案できたら、私はそれを感謝します。何がうまくいかないのか、理由を説明することができれば、さらにうまくいきます。

ありがとうございます!

EDIT:これまでのコメントの

感謝。

ユーザがthis_row.append(s.cell(row,col))(たとえば、s.cell_valueの代わりにs.cell)の場合、ドキュメント全体がエラーなしで書き込まれます。

出力は特に望ましくはありませんが(text:u'516-7773167')、問題の文字が出力に残っていてもエラーは発生しません。

これは結局チャレンジがxlrdにあると思うかもしれません。

思考?

+0

誰がエラーを投げているのかを知るために、トレースバック全体を確認すると便利です。 – Christopher

+0

これ以上見ることはできません: ファイル "the_script。(ascii)codecは位置5の文字 '' xed 'をエンコードできません:序数が範囲内にありません。 (128) – anschauung

+0

"Excelからの出力をUnicodeで"とすると、 "Excelからの出力をUTF-16で"という意味になります。Unicodeは、UTF-8やUTF-16のような異なるエンコーディングシステムで表現されるコードスペースを定義します。 – Svante

答えて

25

私はcell_value戻り値はあなたがこの1行を変更することにより、それを解決することができるはず、その場合、問題を(それを確認するために、そのtype()を印刷してください)、与えているUnicode文字列である期待:

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) 
+0

パーフェクト!それがそれでした。私は、異なる価値の種類が異なって扱われる必要があるとは思わなかったと思います。ありがとう! – anschauung

0

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

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

それが問題でない場合は、あなたのための別のオプションは、出力のラッパーご.CSVとしてcodecs.EncodedFile(ファイル、入力[、出力[、エラー]])を使用することです:

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) 

は、私は右の問題を理解すると仮定して、ファイルへの書き込み時にエラーがスローされると仮定して、あなたのための問題を解決することができます。

+0

まあ、これは別のエラーメッセージを出しました(今回は何も書いていません)。 UnicodeDecodeError: 'utf16'コーデックは938のバイト0x0aをデコードできません:切り捨てられたデータ – anschauung

0

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

このセルには何かがあります.'7 'はASCII範囲内にあるので、' u'x37 'としてエンコードする必要があります。

は、さらに重要な、しかし、あなたはasciiコーデックが使用できないことを指定したエラーメッセージを取得しているという事実は、Unicodeにあなたのエンコーディングで何かの間違ったことを示唆している - それはあなたがその可能な値0xedをエンコードしようとしていると考えてASCIIで表現されていますが、Unicodeで表現しようとしています。

私は問題を引き起こしている特定の行を解決するには十分スマートではありません。あなたの質問を編集して、そのエラーメッセージの原因となった行を教えたら、もう少し手助けできるかもしれません(どちらでもthis_row.append(s.cell_value(row,col))またはbcw.writerow(this_row)ですが、ご確認いただきありがとうございます)。

+0

ありがとう!エラーはbcw.writerowにあります。たとえば、print this_rowを使用すると、すべてが正しく出力されます。 私が知る限り、「7」は明らかに間違っていることはありません。stdoutに出力すると正しく出力されます(u'516-7773167 ')。 – anschauung

+0

それで 'bcw.writerow'がASCIIを期待しているようです - あなたは' csv.writer'の正しい引数を得ているでしょうか?(http://docs.python.org/library/csv.html#csvを見てください)ライター)?私は '0xed'がどこから来ているかに夢中です。 –

9

あなたは説明を求めましたが、現象のいくつかは、あなたの助けなしに不可解です。

(A)Excel 97以降で作成されたXLSファイルの文字列は、可能であればUTF16LEでLatin1でエンコードされます。各文字列には、どちらが使用されたかを示すフラグが付いています。以前のコード化された文字列をユーザーの "コードページ"に従って抽出します。いずれにしても、xlrdはユニコードオブジェクトを生成します。ファイルのエンコーディングは、コードページが省略されているか、またはそれに関するものであるサードパーティのソフトウェアによって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 - これは私がドキュメント与えられた期待するものについてですon 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」に到着しましたか?

THIRDLYの場合、エラーメッセージは実際にはオフセット5(つまり6番目の文字)のユニコード文字「 'xed」について不平を言っています。 U + 00EDはラテン小文字ですが、私は急いでいて、「516-7773167」には何もありません。

4つ目は、エラーの位置が動くターゲットのようです。解決策: "エラーはbcw.writerowにあります。"ハァッ? str(a_unicode_object)は、ユニコードオブジェクトをstrオブジェクトに変換しようとしますが、エンコーディング情報がない場合はasciiを使用しますが、ASCII以外のデータがある場合は、だからスプラット。あなたのオブジェクトはutf8でエンコードされたcsvファイルを生成することですが、単純化されたスクリプトはどこにでもutf8は言及していません。 s.cell_value)の代わりに、s.cell_value)の代わりに、シェイプを使用すると、ドキュメント全体がエラーなく書き込まれます。出力は特に望ましくありません(テキスト:u'516-7773167 「) 『』」CSVライターがあなたのCellオブジェクトの__str__メソッドを呼び出して、これは、デバッグのために有用である可能性が<type>:<repr(value)>を生成するが、あなたのcsvファイルではそれほど大きくない言うように。

ので起こって

(F)Alex Martelliの解答は素晴らしいですが、xlrd docsの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 
+1

+1:素晴らしい説明とバックグラウンドのリンクをありがとう。これは、私がもうエンコーディングについて教育することを避けることができないことを実感しました。すぐに問題が解決された後でさえも、そのような詳細へのあなたのご理解に感謝しています。 – anschauung

関連する問題