带有UTF-8数据的Python CSV DictReader

时间:2011-02-15 14:11:40

标签: python unicode csv

AFAIK,Python(v2.6)csv模块默认无法处理unicode数据,对吗?在Python文档中,有一个关于如何从UTF-8编码文件中读取的example。但是此示例仅将CSV行作为列表返回。 我希望按名称访问行列,因为它由csv.DictReader完成,但使用UTF-8编码的CSV输入文件。

有谁能告诉我如何以有效的方式做到这一点?我将不得不以100的MByte格式处理CSV文件。

7 个答案:

答案 0 :(得分:50)

我自己想出了一个答案:

def UnicodeDictReader(utf8_data, **kwargs):
    csv_reader = csv.DictReader(utf8_data, **kwargs)
    for row in csv_reader:
        yield {unicode(key, 'utf-8'):unicode(value, 'utf-8') for key, value in row.iteritems()}

注意:这已经更新,因此根据评论中的建议解码密钥

答案 1 :(得分:2)

对我来说,关键不是操纵csv DictReader args,而是操纵文件打开器本身。这可以达到目的:

with open(filepath, mode="r", encoding="utf-8-sig") as csv_file:
    csv_reader = csv.DictReader(csv_file)

不需要特殊的课程。现在,无论有没有BOM,我都可以打开文件而不会崩溃。

答案 2 :(得分:0)

首先,使用2.6 version of the documentation。它可以针对每个版本进行更改。它清楚地表明它不支持Unicode,但它确实支持UTF-8。 Technically,这些不是一回事。正如文档所说:

  

csv模块不直接支持读取和写入Unicode,但除了ASCII NUL字符的某些问题外,它还是8位清除。因此,只要您避免使用像UTF-16这样使用NUL的编码,您就可以编写处理编码和解码的函数或类。建议使用UTF-8。

下面的示例(来自文档)显示了如何创建两个正确读取文本为UTF-8为CSV的函数。您应该知道csv.reader()总是返回一个DictReader对象。

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.DictReader(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]

答案 3 :(得分:0)

基于分类的@LMatter回答方法,通过这种方法,您仍然可以获得DictReader的所有好处,例如获取字段名并获取行号以及它处理UTF-8

import csv

class UnicodeDictReader(csv.DictReader, object):

    def next(self):
        row = super(UnicodeDictReader, self).next()
        return {unicode(key, 'utf-8'): unicode(value, 'utf-8') for key, value in row.iteritems()}

答案 4 :(得分:0)

csvw package还具有其他功能(用于Web上的元数据丰富的CSV),但是它定义了一个UnicodeDictReader类,围绕其UnicodeReader类,该类实际上是正是这样:

class UnicodeReader(Iterator):
    """Read Unicode data from a csv file."""
    […]

    def _next_row(self):
        self.lineno += 1
        return [
            s if isinstance(s, text_type) else s.decode(self._reader_encoding)
            for s in next(self.reader)]

它确实使我失望了几次,但是csvw.UnicodeDictReader 确实确实需要在with块中使用,否则会中断。除此之外,该模块非常通用,并且与py2和py3都兼容。

答案 5 :(得分:0)

答案没有DictWriter方法,因此这是更新的类:

class DictUnicodeWriter(object):

    def __init__(self, f, fieldnames, dialect=csv.excel, encoding="utf-8", **kwds):
        self.fieldnames = fieldnames    # list of keys for the dict
        # Redirect output to a queue
        self.queue = cStringIO.StringIO()
        self.writer = csv.DictWriter(self.queue, fieldnames, dialect=dialect, **kwds)
        self.stream = f
        self.encoder = codecs.getincrementalencoder(encoding)()

    def writerow(self, row):
        self.writer.writerow({k: v.encode("utf-8") for k, v in row.items()})
        # Fetch UTF-8 output from the queue ...
        data = self.queue.getvalue()
        data = data.decode("utf-8")
        # ... and reencode it into the target encoding
        data = self.encoder.encode(data)
        # write to the target stream
        self.stream.write(data)
        # empty queue
        self.queue.truncate(0)

    def writerows(self, rows):
        for row in rows:
            self.writerow(row)

    def writeheader(self):
        header = dict(zip(self.fieldnames, self.fieldnames))
        self.writerow(header)

答案 6 :(得分:0)

使用unicodecsv软件包很容易。

# pip install unicodecsv
import unicodecsv as csv

with open('your_file.csv') as csvfile:
    reader = csv.DictReader(csvfile)
    for row in reader:
        print(row)