JSON의 작은 따옴표와 큰 따옴표


107

내 코드 :

import simplejson as json

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

#1 정의가 잘못되었습니다

#2 정의가 맞다

파이썬에서는 작은 따옴표 와 따옴표를 바꿀 수 있다고 들었습니다 . 누구든지 나에게 이것을 설명 할 수 있습니까?

답변:


169

JSON 구문 은 Python 구문 이 아닙니다. JSON에는 문자열에 큰 따옴표가 필요합니다.


2
하지만 첫 번째는 JSON의 작은 따옴표입니다. 혼란 스럽습니다. 하나는 컴파일을 통과 할 수 있지만 두 번째는 통과 할 수 없습니다.
Bin Chen

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

124

당신이 사용할 수있는 ast.literal_eval()

>>> import ast
>>> s = "{'username':'dfdsfdsf'}"
>>> ast.literal_eval(s)
{'username': 'dfdsfdsf'}

9
이 대답이 가장 마음에 듭니다. 선택의 여지가없는 경우가 많습니다. 누군가가 작은 따옴표를 주면 작은 따옴표를 얻게됩니다. json.loads에 추가 인수가 필요하거나이를 사용해야합니다. 들어오는 데이터가 다음과 같은 경우 " '"를 전역 적으로 대체하는 것은 재앙입니다.{ 'a' : 'this "string" really isn\'t!!!!' }
Mark Gerolimatos

@Mark,이 방법은 중첩 된 따옴표가있는 까다로운 상황에 적용 할 수 "{'link':'<a href="mylink">http://my.com</a>'}"있습니까? 이 경우, ast.literal_eval구문 오류가 발생합니다
alancalvitti

1
이것은 나에게 보안 위험처럼 보입니다.
JacksonHaenchen 19

2
이것은 질문에 어떻게 대답합니까? 이것이 JSON의 작은 따옴표와 큰 따옴표와 어떤 관련이 있습니까? 이 ast 접근 방식을 사용하면 문자열에서 Python dict를로드 할 수 있지만 OP의 주요 문제는 문자열 # 1이 유효한 JSON이 아니라 문자열 # 2가 있다는 것입니다.
jschultz410

43

다음과 같이 큰 따옴표로 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
이것은 잘못된 방향입니다. 파이썬 데이터 구조를 JSON으로 직렬화하고 있습니다. 원래 질문은 JSON을 파이썬 데이터 구조로 역 직렬화하는 것입니다.
tedder42

5
아이디어는 json.dumps를 사용하여 파이썬을 json으로 직렬화 한 다음 str 형식 일 때 json.loads를 호출하는 것입니다.
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더 나은 일치이며 훨씬 빠릅니다.


4
demjson.decode손상된 json을위한 훌륭한 도구이지만, 수만 또는 수십만 개의 json 패킷과 관련된 작업의 ast.literal_eval경우 훨씬 빠릅니다. 말할 demjson필요가 없습니다. 더 빠른 방법이 실패 할 경우 대비책으로 사용합니다.
mjwunderlich

1
실제로 demjson은 ast.literal_eval 및 json.loads에 대해 테스트하는 대신 훨씬 더 잘 작동합니다.
Marware

4

예를 들어 하나가 그러한 비표준 JSON을 스트리밍하는 경우 지금까지 답변에 대한 두 가지 문제가 있습니다. 그러면 들어오는 문자열 (파이썬 사전이 아님)을 해석해야 할 수 있기 때문입니다.

문제 1- demjson: Python 3.7. + 및 conda를 사용하면 현재 Python 3.5 이상을 지원하지 않기 때문에 demjson을 설치할 수 없었습니다. 따라서 예를 들어 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)

주입 공격을 방지하려면 eval 대신 ast.literal_eval을 사용하십시오.
Simon Kingaby

2

말했듯이 JSON은 Python 구문이 아닙니다. JSON에서 큰 따옴표를 사용해야합니다. 제작자는 프로그래머의인지 과부하를 완화하기 위해 허용 가능한 구문의 엄격한 하위 집합을 사용하는 것으로 유명합니다.


@Jiaaro가 지적한 것처럼 JSON 문자열 자체에 작은 따옴표가 포함되어 있으면 아래가 실패 할 수 있습니다. 사용하지 마세요. 작동하지 않는 예를 여기에 남겨 두었습니다.

JSON 문자열에 작은 따옴표가 없다는 것을 아는 것은 정말 유용 합니다. 예를 들어 브라우저 콘솔에서 복사하여 붙여 넣었습니다. 그런 다음 입력 할 수 있습니다.

a = json.loads('very_long_json_string_pasted_here')

작은 따옴표도 사용하면 깨질 수 있습니다.


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)

이것은 매우 나쁜 예입니다. 누군가가 당신이 json에서 eval을 사용하고 있다는 것을 알고 eval에 의해 평가되는 코드가 포함 된 잘못된 json을 보내면 어떻게 될까요?
Metonymy

1

나는 최근에 매우 유사한 문제에 대해 생각해 냈고 내 솔루션이 당신에게도 효과가 있다고 믿습니다. 다음과 같은 형식의 항목 목록이 포함 된 텍스트 파일이 있습니다.

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

위의 내용을 파이썬 목록으로 구문 분석하고 싶었지만 입력을 신뢰할 수 없기 때문에 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 에서 얻을 수없는 것은 무엇입니까 ?
Charles Duffy

0
import ast 
answer = subprocess.check_output(PYTHON_ + command, shell=True).strip()
    print(ast.literal_eval(answer.decode(UTF_)))

나를 위해 작동


-4
import json
data = json.dumps(list)
print(data)

위의 코드 스 니펫이 작동합니다.


2
유용한 일을 할 수는 있지만 질문에 답하지 않습니다. 문제는 목록이 아닌 문자열로 시작됩니다.
Rachel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.