带有 UTF-8 数据的 Python CSV DictReader

Posted

技术标签:

【中文标题】带有 UTF-8 数据的 Python CSV DictReader【英文标题】:Python CSV DictReader with UTF-8 data 【发布时间】:2011-06-27 15:25:12 【问题描述】:

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

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

【问题讨论】:

【参考方案1】:

我自己想出了一个答案:

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

注意:这已更新,因此密钥会根据 cmets 中的建议进行解码

【讨论】:

然后选择它作为答案:) 好的,不知道我能做到这一点:) 我会等一段时间看看是否有人知道更好的方法,然后接受它。 -1 这不会解码文件第一行中的字典键。 无需为回答您自己的问题而道歉。这是 *** 的预期用途之一。现在其他人都可以分享您自学的内容! 正如 John Machin 提到的,这不会解码密钥; yield 行应该是: yield unicode(key, 'utf-8'):unicode(value, 'utf-8') for key, value in row.iteritems()【参考方案2】:

对我来说,关键不在于操纵 csv DictReader args,而在于文件打开器本身。这成功了:

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

不需要特殊课程。现在我可以打开带有或不带有 BOM 的文件而不会崩溃。

【讨论】:

TypeError: 'encoding' is an invalid keyword argument for this function @ATX Odd - 我想知道你是在 python2 上而不是 3 上吗? 是的,确实是 p2【参考方案3】:

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

csv 模块不直接支持读写 Unicode,但它是 8-bit-clean 保存 ASCII NUL 字符的一些问题。因此,只要您避免使用像 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]

【讨论】:

csv.reader() 在我测试时不返回 DictReader 对象。您确定吗?此外,您的示例中的 yield 语句仅返回一个包含值的列表,而不是一个字典。 我猜你对 DictReader 的看法是正确的。我将示例更改为调用csv.DictReader 而不是csv.reader。请注意,除了这个差异之外,这直接在文档之外。 我认为你的读者仍然没有返回一个字典,而只是一个行值列表(参见 yield 语句)。但是感谢您的回答,无论如何,在重新阅读您提到的文档后,我自己想出了一个解决方案(最后:)) @LMatter 你介意分享你找到的解决方案吗?【参考方案4】:

@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()

【讨论】:

【参考方案5】:

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

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 兼容。

【讨论】:

【参考方案6】:

答案没有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)

【讨论】:

【参考方案7】:

使用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)

【讨论】:

以上是关于带有 UTF-8 数据的 Python CSV DictReader的主要内容,如果未能解决你的问题,请参考以下文章

无法将带有塞浦路斯数据的csv文件上传到Google数据工作室-编码utf-8错误

如何将带有中文字符的 CSV UTF-8 文件导入 MySQL?

python数据分析-数据处理

Python 建模步骤

将 utf-8 格式的 Python 列表写入 CSV

如何从带有额外分隔符的 csv 在 python 中创建 pandas 数据框?