2013-07-07 5 views
0

Я пытаюсь использовать следующий код (в пределах web2py) для чтения файла CSV и конвертировать его в формате JSON объект:питона: CSV для преобразования JSON, когда CSV содержит юникод

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' codec can't decode byte 0xa0 in position 1: invalid start byte

По-видимому, существует проблема с обработкой пробелов в 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, который не будет производить подобные осложнения ? Спасибо.

+0

Это Python 2 или 3? Пожалуйста, включите * full * traceback. –

+1

Вам не нужно использовать понимание списка, где будет выполняться простой вызов 'list()': 'json.dumps (list (csv_reader))' будет более эффективным. –

+2

И последнее, но не менее важное: вам нужно поделиться тем, как вы читаете файл с нами. Что такое веб-инфраструктура? –

ответ

2

Попробуйте заменить вашу последнюю строку с

json = json.dumps([x.encode('utf-8') for x in csv_reader]) 
+0

Специфическим символом, вызывающим проблему в данном конкретном случае, является «\ xa0»; encode ('utf-8') создает ошибку при ее встрече. – Lamps1829

1

Запуск unidecode над содержимым файла, кажется, сделать трюк:

from isounidecode import unidecode 

... 

file_contents = unidecode(file_stream.read()) 

... 

Спасибо, все!

+1

Это заменяет все символы, отличные от ASCII, с искаженными версиями ASCII с наилучшими настройками - вы уверены, что хотите это сделать? – bobince

+0

Вы делаете хороший момент. Это может быть не универсальное решение, но работает для моих целей и, по-видимому, лучше, чем некоторые другие варианты при работе со множеством случаев таким образом, чтобы не возникала ошибка (в отличие от encode(), которая срабатывает например, '\ xa0'). – Lamps1829

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 сможет справиться с ними в порядке. Unfortately 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)) 

it's not known in advance what sort of encoding will come up

Ну вот еще проблема, так как невозможно угадать точно, что кодирование файла. Вы должны либо указать конкретную кодировку, либо дать пользователю способ сообщить, что такое кодировка, если вы хотите правильно поддерживать символы, отличные от ASCII.

Смежные вопросы