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

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

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

【问题讨论】:

    标签: python unicode 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 这不会解码文件第一行中的字典键。
    • 无需为回答您自己的问题而道歉。这是 stackoverflow 的预期用途之一。现在其他人都可以分享您自学的内容!
    • 正如 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)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2023-03-26
            • 2011-10-03
            • 1970-01-01
            • 2012-04-20
            • 2013-11-28
            • 1970-01-01
            • 2011-12-14
            相关资源
            最近更新 更多