web-dev-qa-db-fra.com

Python json.loads échoue avec `ValueError: caractère de contrôle non valide à: ligne 1 colonne 33 (caractère 33)`

J'ai une chaîne comme celle-ci:

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) renvoie un message d'erreur comme ceci:

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

Pourquoi cette erreur se produit? Comment puis-je résoudre ce problème?

39
福气鱼

Le problème est que votre chaîne unicode contient des retours chariot (\r) et des nouvelles lignes (\n) au sein de un littéral de chaîne dans les données JSON. S'ils étaient censés faire partie de la chaîne elle-même, ils devraient être échappés de manière appropriée. S'ils ne faisaient pas partie de la chaîne, ils ne devraient pas non plus figurer dans votre code JSON.

Si vous ne pouvez pas déterminer où vous avez obtenu cette chaîne JSON pour produire du JSON valide, vous pouvez soit supprimer les caractères incriminés:

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

ou leur échapper manuellement:

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

Une autre option consiste peut-être à utiliser l'argument strict=False

Selon http://docs.python.org/2/library/json.html

"Si strict est False (True est la valeur par défaut), les caractères de contrôle sont autorisés dans les chaînes. Les caractères de contrôle dans ce contexte sont ceux avec des codes de caractères compris entre 0 et 31, y compris '\ t' (tab), '\ n ','\r 'et'\0 '. "

Par exemple:

json.loads(json_str, strict=False)
91
drpoo

Le problème est que le caractère à l'index 33 est un caractère de contrôle de retour chariot.

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

Selon les spécifications JSON, les caractères valides sont les suivants:

  • N'importe quel caractère Unicode sauf: ", \ et les caractères de contrôle (ord(char) < 32).

  • Les séquences de caractères suivantes sont autorisées: \", \\, \/, \b (retour arrière), \f (formulaire), \n (saut de ligne/nouvelle ligne), \r (retour chariot), \t (tabulation) ou \u suivi de quatre chiffres hexadécimaux.

Toutefois, en Python, vous devrez doubler les caractères de contrôle d'échappement (à moins que la chaîne ne soit brute), car Python interprète également ces caractères de contrôle.

>>> 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'}

Références:

11
cpburnz

Essayez d'échapper à vos \n et \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'}
7
Bogdan

Dans certains cas, cette erreur sera générée lorsque le fichier contient en réalité une chaîne contenant des espaces. Supprimer les espaces résoudra le problème.

0
sheldonkreger