Одинарные и двойные кавычки в JSON

109

Мой код:

import simplejson as json

s = "{'username':'dfdsfdsf'}" #1
#s = '{"username":"dfdsfdsf"}' #2
j = json.loads(s)

#1 определение неверно

#2 определение правильное

Я слышал, что в Python одинарные и двойные кавычки могут быть взаимозаменяемыми. Кто-нибудь может мне это объяснить?

Бин Чен
источник

Ответы:

170

Синтаксис JSON не является синтаксисом Python. JSON требует двойных кавычек для своих строк.

Игнасио Васкес-Абрамс
источник
2
но сначала это одинарная кавычка в JSON, я смущен. Один может пройти компиляцию, а второй - нет.
Бин Чен,
6
Спасибо за это подтверждение. Видимо, импортирую только я str(dict)и не хочу evalэтого. Простой .replace("'", '"')должен сделать свое дело.
isaaclw
8
И я заговорил слишком рано. Видимо, все сложнее.
isaaclw
6
Если вам нужно использовать двойные кавычки вокруг, вы можете json.dumps(..)дважды вызвать, как в:, import json; d = dict(tags=["dog", "cat", "mouse"]); print json.dumps(json.dumps(d))что дает:"{\"tags\": [\"dog\", \"cat\", \"mouse\"]}"
rprasad
125

ты можешь использовать ast.literal_eval()

>>> import ast
>>> s = "{'username':'dfdsfdsf'}"
>>> ast.literal_eval(s)
{'username': 'dfdsfdsf'}
hahakubile
источник
9
Мне больше всего нравится этот ответ: у вас не часто есть выбор: если кто-то дает вам одинарные кавычки, вы получаете одинарные кавычки. Либо json.loads нужен дополнительный аргумент, либо вы должны его использовать. Глобальная замена "" - это катастрофа, а что, если бы входящие данные были { 'a' : 'this "string" really isn\'t!!!!' }
такими
@Mark, можно ли адаптировать этот метод к более сложной ситуации с вложенными кавычками, например "{'link':'<a href="mylink">http://my.com</a>'}"? В этом случае ast.literal_evalвыдает синтаксическую ошибку
alancalvitti
1
Мне это кажется угрозой безопасности.
JacksonHaenchen
2
Как это отвечает на вопрос? Какое отношение это имеет к одинарным и двойным кавычкам в JSON? Этот подход ast может позволить вам загрузить Python dict из строки, но основная проблема OP заключается в том, что строка №1 недействительна JSON, а строка №2 -.
jschultz410
44

Вы можете сбросить JSON с двойной кавычкой:

import json

# mixing single and double quotes
data = {'jsonKey': 'jsonValue',"title": "hello world"}

# get string with all double quotes
json_string = json.dumps(data) 
ковбой
источник
12
это идет не так. вы сериализуете структуры данных Python в JSON; исходный вопрос касается десериализации JSON в структуры данных python.
tedder42
5
Идея состоит в том, чтобы сериализовать python в json с помощью json.dumps, а затем вызвать json.loads для него, когда он находится в форме str.
jheld
3
Вы здесь не понимаете. Если вы хотите загрузить строку json, это должны быть двойные кавычки. То, что вы делаете, по-прежнему сбрасывает json, а не строку json.
LegitMe
12

demjson также является хорошим пакетом для решения проблемы плохого синтаксиса json:

pip install demjson

Использование:

from demjson import decode
bad_json = "{'username':'dfdsfdsf'}"
python_dict = decode(bad_json)

Редактировать:

demjson.decode- отличный инструмент для поврежденного json, но когда вы имеете дело с большим количеством данных json, ast.literal_evalон лучше подходит и намного быстрее.

DhiaTN
источник
4
demjson.decode- отличный инструмент для поврежденного json, но для задач, включающих десятки или сотни тысяч json-пакетов, ast.literal_evalон намного быстрее. Не сказать demjson, что в нем нет места: я использую его как запасной вариант на случай, если более быстрые методы не работают.
mjwunderlich
1
На самом деле, demjson работал намного лучше, вместо тестирования с ast.literal_eval и json.loads
Marware
5

На данный момент даны две проблемы с ответами, если, например, один передает такой нестандартный JSON. Потому что тогда, возможно, придется интерпретировать входящую строку (а не словарь Python).

Проблема 1 - demjson: с Python 3.7. + И использованием conda мне не удалось установить demjson, поскольку он, очевидно, в настоящее время не поддерживает Python> 3.5. Поэтому мне нужно решение с более простыми средствами, например astи / или json.dumps.

Проблема 2 - ast& json.dumps: если JSON заключен в одинарные кавычки и содержит строку как минимум в одном значении, которое, в свою очередь, содержит одинарные кавычки, единственное простое, но практическое решение, которое я нашел, - это применение обоих:

В следующем примере мы предполагаем, lineчто это входящий строковый объект JSON:

>>> line = str({'abc':'008565','name':'xyz','description':'can control TV\'s and more'})

Шаг 1: преобразуйте входящую строку в словарь, используя ast.literal_eval()
Шаг 2: примените json.dumpsк нему для надежного преобразования ключей и значений, но не затрагивая содержимое значений :

>>> import ast
>>> import json
>>> print(json.dumps(ast.literal_eval(line)))
{"abc": "008565", "name": "xyz", "description": "can control TV's and more"}

json.dumpsсам по себе не справился бы с этой задачей, потому что он не интерпретирует JSON, а только видит строку. Аналогично ast.literal_eval(): хотя он правильно интерпретирует JSON (словарь), он не преобразует то, что нам нужно.

Зигфрид Хайде
источник
3

Вы можете исправить это так:

s = "{'username':'dfdsfdsf'}"
j = eval(s)
Робин Али
источник
используйте ast.literal_eval вместо eval, чтобы избежать атак инъекциями
Саймон Кингаби
2

Как уже говорилось, JSON - это не синтаксис Python. В JSON нужно использовать двойные кавычки. Его создатель (не) известен тем, что использует строгие подмножества допустимого синтаксиса для облегчения когнитивной перегрузки программиста.


Ниже может произойти сбой, если одна из строк JSON сама по себе содержит одну кавычку, как указано @Jiaaro. НЕ ИСПОЛЬЗУЙ. Оставил здесь как пример того, что не работает.

Это действительно полезно знать , что нет одинарных кавычек в строке JSON. Скажем, вы скопировали и вставили его из консоли браузера / чего угодно. Затем вы можете просто ввести

a = json.loads('very_long_json_string_pasted_here')

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

serv-inc
источник
2
неверно, что в строке json нет одинарных кавычек. Это может быть правдой в конкретном случае, но на это нельзя полагаться. например, это действительный json:{"key": "value 'with' single quotes"}
Jiaaro
2

Это действительно решило мою проблему с помощью функции eval.

single_quoted_dict_in_string = "{'key':'value', 'key2': 'value2'}"
desired_double_quoted_dict = eval(single_quoted_dict_in_string)
# Go ahead, now you can convert it into json easily
print(desired_double_quoted_dict)
Хафиз Хашим
источник
Это очень плохой пример. Что, если кто-то узнает, что вы используете eval в json, и отправит искаженный json, содержащий код, который затем оценивается eval?
Метонимия
1

Недавно я столкнулся с очень похожей проблемой и считаю, что мое решение сработает и для вас. У меня был текстовый файл, содержащий список элементов в форме:

["first item", 'the "Second" item', "thi'rd", 'some \\"hellish\\" \'quoted" item']

Я хотел разобрать приведенное выше в список Python, но мне не нравился eval (), так как я не мог доверять входным данным. Сначала я попробовал использовать JSON, но он принимает только элементы в двойных кавычках, поэтому я написал свой собственный очень простой лексер для этого конкретного случая (просто вставьте свой собственный "stringtoparse", и вы получите в виде списка вывода: 'items')

#This lexer takes a JSON-like 'array' string and converts single-quoted array items into escaped double-quoted items,
#then puts the 'array' into a python list
#Issues such as  ["item 1", '","item 2 including those double quotes":"', "item 3"] are resolved with this lexer
items = []      #List of lexed items
item = ""       #Current item container
dq = True       #Double-quotes active (False->single quotes active)
bs = 0          #backslash counter
in_item = False #True if currently lexing an item within the quotes (False if outside the quotes; ie comma and whitespace)
for c in stringtoparse[1:-1]:   #Assuming encasement by brackets
    if c=="\\": #if there are backslashes, count them! Odd numbers escape the quotes...
        bs = bs + 1
        continue                    
    if (dq and c=='"') or (not dq and c=="'"):  #quote matched at start/end of an item
        if bs & 1==1:   #if escaped quote, ignore as it must be part of the item
            continue
        else:   #not escaped quote - toggle in_item
            in_item = not in_item
            if item!="":            #if item not empty, we must be at the end
                items += [item]     #so add it to the list of items
                item = ""           #and reset for the next item
            continue                
    if not in_item: #toggle of single/double quotes to enclose items
        if dq and c=="'":
            dq = False
            in_item = True
        elif not dq and c=='"':
            dq = True
            in_item = True
        continue
    if in_item: #character is part of an item, append it to the item
        if not dq and c=='"':           #if we are using single quotes
            item += bs * "\\" + "\""    #escape double quotes for JSON
        else:
            item += bs * "\\" + c
        bs = 0
        continue

Надеюсь, это кому-нибудь пригодится. Наслаждайтесь!

Мэтт
источник
Чего вы не получаете от docs.python.org/2/library/ast.html#ast.literal_eval ?
Чарльз Даффи
-1
import ast 
answer = subprocess.check_output(PYTHON_ + command, shell=True).strip()
    print(ast.literal_eval(answer.decode(UTF_)))

Работает для меня

vaibhav.patil
источник
-4
import json
data = json.dumps(list)
print(data)

Приведенный выше фрагмент кода должен работать.

Дирадж Р.
источник
2
Он может сделать что-то полезное, но не отвечает на заданный вопрос. Проблема начинается со строки, а не со списка.
Рэйчел