【问题标题】:python: csv to json conversion when csv contains unicodepython:当csv包含unicode时,csv到json转换
【发布时间】:2013-07-05 01:38:57
【问题描述】:

我正在尝试使用以下代码(在 web2py 中)读取 csv 文件并将其转换为 json 对象:

import csv
import json

originalfilename, file_stream = db.tablename.file.retrieve(info.file) 
file_contents =   file_stream.read()

csv_reader = csv.DictReader(StringIO(file_contents))
json = json.dumps([x for x in csv_reader])

这会产生以下错误:

'utf8' 编解码器无法解码字节 位置 1 中的 0xa0:无效的起始字节

显然,处理 .csv 文件中的空格存在问题。问题似乎源于 json.dumps() 行。从那时起的追溯:

Traceback (most recent call last):
  File ".../web2py/gluon/restricted.py", line 212, in restricted
    exec ccode in environment
  File ".../controllers/default.py", line 2345, in <module>
  File ".../web2py/gluon/globals.py", line 194, in <lambda>
    self._caller = lambda f: f()
  File ".../web2py/gluon/tools.py", line 3021, in f
    return action(*a, **b)
  File ".../controllers/default.py", line 697, in generate_vis
    request.vars.json = json.dumps(list(csv_reader))
  File "/usr/local/lib/python2.7/json/__init__.py", line 243, in dumps
    return _default_encoder.encode(obj)
  File "/usr/local/lib/python2.7/json/encoder.py", line 207, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/local/lib/python2.7/json/encoder.py", line 270, in iterencode
    return _iterencode(o, 0)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xa0 in position 1: invalid start byte

关于如何解决此问题的任何建议,或将 csv 文件(包含标头;使用 StringIO)放入不会产生类似并发症的 json 对象的其他方法?谢谢。

【问题讨论】:

  • 这是 Python 2 还是 3?请务必包含完整回溯。
  • 您不需要使用列表推导,而简单的list() 调用就可以做到:json.dumps(list(csv_reader)) 会更有效。
  • 最后但同样重要的是,您需要与我们分享您阅读文件的方式。这是什么网络框架?
  • 请澄清错误的确切行。
  • python pandas 提供了非常方便的方式或处理 csv 文件:pandas.pydata.org/pandas-docs/stable/generated/…,如果有帮助的话

标签: python json csv unicode stringio


【解决方案1】:

尝试用

替换你的最后一行
json = json.dumps([x.encode('utf-8') for x in csv_reader])

【讨论】:

  • 在这种特殊情况下导致问题的特定字符是 '\xa0'; encode('utf-8') 遇到时会报错。
【解决方案2】:

对文件内容运行 unidecode 似乎可以解决问题:

from isounidecode import unidecode

...

file_contents =   unidecode(file_stream.read())

...

谢谢大家!

【讨论】:

  • 这是用最合适的 ASCII 版本替换所有非 ASCII 字符 - 你确定要这样做吗?
  • 你说得很好。它可能不是一个通用的解决方案,但适用于我的目的,并且在处理多种情况时似乎比其他一些选项更好,不会产生错误(与编码()相反,它会被绊倒以 '\xa0' 为例)。
【解决方案3】:

csv 模块(在 Python 2 下)是纯粹基于字节的;你从中得到的所有字符串都是字节。然而 JSON 是基于 Unicode 字符的,因此当您尝试将从 CSV 获得的字节写出到 JSON 时存在隐式转换。 Python 对此猜测为 UTF-8,但您的 CSV 文件不是 UTF-8 - 它可能是 Windows 代码页 1252(西欧 - 只是不太像 ISO-8859-1)。

快速解决方法是对您的输入 (file_contents= file_contents.decode('windows-1252').encode('utf-8')) 进行转码,但您可能并不想依赖 json 猜测特定的编码。

最好在从 CSV 读取字符串时显式解码它们。然后JSON就能应付他们OK了。不幸的是csv没有内置解码(至少在这个Python版本中),但你可以手动完成:

class UnicodeDictReader(csv.DictReader):
    def __init__(self, f, encoding, *args, **kwargs):
        csv.DictReader.__init__(self, f, *args, **kwargs)
        self.encoding = encoding
    def next(self):
        return {
            k.decode(self.encoding): v.decode(self.encoding)
            for (k, v) in csv.DictReader.next(self).items()
        }

csv_reader = UnicodeDictReader(StringIO(file_contents), 'windows-1252')
json_output = json.dumps(list(csv_reader))

事先不知道会出现什么样的编码

这是一个更大的问题,因为不可能准确地猜测文件的编码。如果你想的话,你要么必须指定特定的编码,要么给用户一种方法来指示编码是什么正确支持非ASCII字符。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-02
    • 2021-08-21
    • 2018-12-25
    • 1970-01-01
    • 2015-08-07
    • 1970-01-01
    • 2018-11-06
    • 2023-03-19
    相关资源
    最近更新 更多