Python json.loads терпит неудачу с `ValueError: Invalid control character at: строка 1 столбец 33 (char 33)`

У меня есть строка вроде этого:

s = u"""{"desc": "\u73cd\u54c1\u7f51-\u5168\u7403\u6f6e\u6d41\u5962\u54c1\u7f51\u7edc\u96f6\u552e\u5546 <br \/>\r\nhttp:\/\/www.zhenpin.com\/ <br \/>\r\n<br \/>\r\n200\u591a\u4e2a\u56fd\u9645\u4e00\u7ebf\u54c1\u724c\uff0c\u9876\u7ea7\u4e70\u624b\u5168\u7403\u91c7\u8d2d\uff0c100%\u6b63\u54c1\u4fdd\u969c\uff0c7\u5929\u65e0\u6761\u2026"}"""

json.loads(s) возвращает сообщение об ошибке следующим образом:

ValueError: Invalid control character at: line 1 column 33 (char 33)

Почему эта ошибка возникает? Как я могу решить эту проблему?

Ответ 1

Проблема заключается в том, что ваша строка в Юникоде содержит возвращаемые каретки (\r) и новые строки (\n) в строковом литерале в данных JSON. Если они должны были быть частью самой строки, они должны быть экранированы соответствующим образом. Если они не должны были быть частью строки, они также не должны быть в вашем JSON.

Если вы не можете исправить, где вы получили эту строку JSON для создания допустимого JSON, вы можете либо удалить оскорбительные символы:

>>> json.loads(s.replace('\r\n', ''))

или выполните их вручную:

>>> json.loads(s.replace('\r\n', '\\r\\n'))

Ответ 2

Другим вариантом, возможно, является использование аргумента strict=False

Согласно http://docs.python.org/2/library/json.html

"Если strict - False (True - значение по умолчанию), тогда управляющие символы будут разрешены внутри строк. Управляющими символами в этом контексте являются символы с кодами символов в диапазоне 0-31, включая '\ t' (tab) '\n', '\ r' и '\ 0'."

Например:

json.loads(json_str, strict=False)

Ответ 3

Проблема заключается в том, что символ в индексе 33 является символом управления возвратом каретки.

>>> s[33]
u'\r'

В соответствии с спецификацией JSON действительными символами являются:

  • Любой символ Юникода, кроме: ", \ и управляющих символов (ord(char) < 32).

  • Разрешены следующие последовательности символов: \", \\, \/, \b (backspace), \f (form feed), \n (line-feed/new- line), \r (возврат каретки), \t (tab) или \u, за которым следуют четыре шестнадцатеричных цифры.

Однако в Python вам придется удвоить символы управления эвакуацией (если строка не является исходной), поскольку Python также интерпретирует эти управляющие символы.

>>> s = ur"""{"desc": "\u73cd\u54c1\u7f51-\u5168\u7403\u6f6e\u6d41\u5962\u54c1\u7f51\u7edc\u96f6\u552e\u5546 <br \/>\r\nhttp:\/\/www.zhenpin.com\/ <br \/>\r\n<br \/>\r\n200\u591a\u4e2a\u56fd\u9645\u4e00\u7ebf\u54c1\u724c\uff0c\u9876\u7ea7\u4e70\u624b\u5168\u7403\u91c7\u8d2d\uff0c100%\u6b63\u54c1\u4fdd\u969c\uff0c7\u5929\u65e0\u6761\u2026"}"""
>>> json.loads(s)
{u'desc': u'\u73cd\u54c1\u7f51-\u5168\u7403\u6f6e\u6d41\u5962\u54c1\u7f51\u7edc\u96f6\u552e\u5546 <br />\r\nhttp://www.zhenpin.com/ <br />\r\n<br />\r\n200\u591a\u4e2a\u56fd\u9645\u4e00\u7ebf\u54c1\u724c\uff0c\u9876\u7ea7\u4e70\u624b\u5168\u7403\u91c7\u8d2d\uff0c100%\u6b63\u54c1\u4fdd\u969c\uff0c7\u5929\u65e0\u6761\u2026'}

Литература:

Ответ 4

Попробуйте избежать \n и \r:

s = s.replace('\r', '\\r').replace('\n', '\\n')
json.loads(s)
>>> {u'desc': u'\u73cd\u54c1\u7f51-\u5168\u7403\u6f6e\u6d41\u5962\u54c1\u7f51\u7edc\u96f6\u552e\u5546 <br />\r\nhttp://www.zhenpin.com/ <br />\r\n<br />\r\n200\u591a\u4e2a\u56fd\u9645\u4e00\u7ebf\u54c1\u724c\uff0c\u9876\u7ea7\u4e70\u624b\u5168\u7403\u91c7\u8d2d\uff0c100%\u6b63\u54c1\u4fdd\u969c\uff0c7\u5929\u65e0\u6761\u2026'}

Ответ 5

В некоторых случаях эта ошибка возникает, когда файл фактически содержит строку с пробелом в ней. Удаление пробела решит проблему.