python:当csv包含unicode时csv到json的转换

时间:2013-07-07 17:33:28

标签: python json csv unicode stringio

我正在尝试使用以下代码(在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对象中?谢谢。

3 个答案:

答案 0 :(得分: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将能够应对它们。不幸的是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字符。

答案 1 :(得分:2)

尝试用

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

答案 2 :(得分:1)

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

from isounidecode import unidecode

...

file_contents =   unidecode(file_stream.read())

...

谢谢大家!