Pythonのcsvモジュールは、UTF-8/Unicodeが含まれていると正しく機能しません。 Pythonのドキュメント や他のWebページで、特定のケースで機能しますが、処理するエンコーディングを十分に理解し、適切なスニペットを使用する必要があります。
Python 2.6で動作する.csvファイルから文字列とUnicode文字列の両方を読み書きするにはどうすればよいですか?または、これはPython 2.6の制限ですか?単純な解決策はありませんか?
http://docs.python.org/library/csv.html#examples で提供されているUnicodeを読み取る方法のコード例は、Python 2.6および2.7。
以下はUnicodeDictReader
です。これはutf-8で動作し、他のエンコーディングでも使用できますが、私はutf-8入力でのみテストしました。
つまり、csv行がcsv.reader
によってフィールドに分割された後にのみUnicodeをデコードするという考え方です。
class UnicodeCsvReader(object):
def __init__(self, f, encoding="utf-8", **kwargs):
self.csv_reader = csv.reader(f, **kwargs)
self.encoding = encoding
def __iter__(self):
return self
def next(self):
# read and split the csv row into fields
row = self.csv_reader.next()
# now decode
return [unicode(cell, self.encoding) for cell in row]
@property
def line_num(self):
return self.csv_reader.line_num
class UnicodeDictReader(csv.DictReader):
def __init__(self, f, encoding="utf-8", fieldnames=None, **kwds):
csv.DictReader.__init__(self, f, fieldnames=fieldnames, **kwds)
self.reader = UnicodeCsvReader(f, encoding=encoding, **kwds)
使用法(ソースファイルエンコーディングはutf-8):
csv_lines = (
"абв,123",
"где,456",
)
for row in UnicodeCsvReader(csv_lines):
for col in row:
print(type(col), col)
出力:
$ python test.py
<type 'unicode'> абв
<type 'unicode'> 123
<type 'unicode'> где
<type 'unicode'> 456
少し遅い答えですが、私は nicodecsv を使用して大きな成功を収めました。
提供されているモジュール here は、utf-8 csvで作業できるcsvモジュールのクールでシンプルなドロップイン置換のように見えます。
import ucsv as csv
with open('some.csv', 'rb') as f:
reader = csv.reader(f)
for row in reader:
print row
doc にはすでにUnicodeの例が使用されていますが、なぜ別の例を見つけるか、ホイールを再発明する必要があるのですか?
import csv
def unicode_csv_reader(unicode_csv_data, dialect=csv.Excel, **kwargs):
# csv.py doesn't do Unicode; encode temporarily as UTF-8:
csv_reader = csv.reader(utf_8_encoder(unicode_csv_data),
dialect=dialect, **kwargs)
for row in csv_reader:
# decode UTF-8 back to Unicode, cell by cell:
yield [unicode(cell, 'utf-8') for cell in row]
def utf_8_encoder(unicode_csv_data):
for line in unicode_csv_data:
yield line.encode('utf-8')
確かに unicodecsv
はcsv
モジュールの優れた代替品です。ソースコードでcsv
をunicodecsv
に置き換えたところですが、これは魅力のように機能します。
pythonドキュメント で言及されているラッパー_unicode_csv_reader
_は、Unicode文字列を受け入れます。これは、csvがUnicode文字列を受け入れないためです。 cvsは、エンコーディングやロケールを認識しておらず、取得した文字列をバイトとして扱います。つまり、ラッパーはUnicode文字列をエンコードし、バイトの文字列を作成します。次に、ラッパーがcsvからの結果を返すと、バイトを再度デコードします。つまり、UTF-8バイトシーケンスを正しいUnicode文字に変換します。
ラッパーにプレーンバイト文字列を指定すると、 f.readlines()
を使用すると、バイト数が127より大きいUnicodeDecodeError
が得られます。プログラムにCSV形式のUnicode文字列がある場合は、ラッパーを使用します。
ラッパーにはまだ1つの制限があると想像できます。cvsはUnicodeを受け入れず、マルチバイト区切り文字も受け入れないため、区切り文字としてUnicode文字を含むファイルを解析できません。
tablib を検討する必要があります。これは完全に異なるアプローチですが、「動作するだけ」という要件の下で検討する必要があります。
with open('some.csv', 'rb') as f:
csv = f.read().decode("utf-8")
import tablib
ds = tablib.Dataset()
ds.csv = csv
for row in ds.dict:
print row["First name"]
警告:tablibは、すべての行に同じ数の項目がない場合、csvを拒否します。
多分これは明らかに明白ですが、初心者のために私はそれを言及します。
python 3.Xでcsv
モジュール は、そのままのエンコーディングをサポートしています 。このバージョンを使用すると、次のことができます。標準モジュールにこだわる。
with open("foo.csv", encoding="utf-8") as f:
r = csv.reader(f, delimiter=";")
for row in r:
print(row)
詳細については、次を参照してください: python 3.1.3はcsvモジュールでUnicodeをサポートしていますか?
Maxim's answer のわずかに改善されたバージョンは、UTF-8 BOMをスキップすることもできます。
import csv
import codecs
class UnicodeCsvReader(object):
def __init__(self, csv_file, encoding='utf-8', **kwargs):
if encoding == 'utf-8-sig':
# convert from utf-8-sig (= UTF8 with BOM) to plain utf-8 (without BOM):
self.csv_file = codecs.EncodedFile(csv_file, 'utf-8', 'utf-8-sig')
encoding = 'utf-8'
else:
self.csv_file = csv_file
self.csv_reader = csv.reader(self.csv_file, **kwargs)
self.encoding = encoding
def __iter__(self):
return self
def next(self):
# read and split the csv row into fields
row = self.csv_reader.next()
# now decode
return [unicode(cell, self.encoding) for cell in row]
@property
def line_num(self):
return self.csv_reader.line_num
class UnicodeDictReader(csv.DictReader):
def __init__(self, csv_file, encoding='utf-8', fieldnames=None, **kwds):
reader = UnicodeCsvReader(csv_file, encoding=encoding, **kwds)
csv.DictReader.__init__(self, reader.csv_file, fieldnames=fieldnames, **kwds)
self.reader = reader
BOMの存在は自動的に検出されないことに注意してください。 UnicodeCsvReader
またはUnicodeDictReader
のコンストラクターにencoding='utf-8-sig'
引数を渡して、そこにあることを通知する必要があります。エンコードutf-8-sig
は、BOMを使用したutf-8
です。
Itsadokの答えを追加します。デフォルトでは、Excelはcsvファイルをlatin-1(ucsvはサポートしていません)として保存します。これは次の方法で簡単に修正できます。
with codecs.open(csv_path, 'rb', 'latin-1') as f:
f = StringIO.StringIO( f.read().encode('utf-8') )
reader = ucsv.UnicodeReader(f)
# etc.