사전의 문자열 표현을 사전으로 변환 하시겠습니까?


767

다음 문자열과 같은 의 str표현을 어떻게?로 변환 할 수 있습니까?dictdict

s = "{'muffin' : 'lolz', 'foo' : 'kitty'}"

나는 사용하지 않는 것이 좋습니다 eval. 다른 무엇을 사용할 수 있습니까?

이것의 주된 이유는 그가 작성한 동료 클래스 중 하나이기 때문에 모든 입력을 문자열로 변환합니다. 나는이 문제를 다루기 위해 수업을 수정하고 기분이 좋지 않습니다.


1
파이썬 2.6을 사용할 수없는 경우, 당신은 같은 간단한 safeeval implmenentation 사용할 수 있습니다 code.activestate.com/recipes/364469 은 총 작업 모두 자신을 할 필요가 없습니다 그래서 파이썬 컴파일러에 편승합니다.
Ned Batchelder

11
참고 : 믿을 수 없을 정도로 유사한 JSON 데이터 가있는 사람들은 대신 Python으로 Parse JSON을 읽으십시오 . JSON은 Python과 다릅니다 . 당신이있는 경우 "귀하의 문자열을 큰 따옴표를 당신은 아마 JSON 데이터를 가지고있다. 당신은 또한 찾아보실 수 있습니다 null, true또는 false, 파이썬 구문 사용을 None, True하고 False.
Martijn Pieters

답변:


1167

파이썬 2.6부터는 내장 함수를 사용할 수 있습니다 ast.literal_eval:

>>> import ast
>>> ast.literal_eval("{'muffin' : 'lolz', 'foo' : 'kitty'}")
{'muffin': 'lolz', 'foo': 'kitty'}

이것은을 사용하는 것보다 안전 eval합니다. 자체 문서에서 말하는 것처럼 :

>>> help (ast.literal_eval)
ast 모듈의 literal_eval 함수에 대한 도움말 :

literal_eval (노드 _ 또는 _ 문자열)
    표현식 노드 또는 파이썬을 포함하는 문자열을 안전하게 평가
    표현. 제공된 문자열 또는 노드는 다음으로 만 구성 될 수 있습니다
    파이썬 리터럴 구조 : 문자열, 숫자, 튜플,리스트, dicts, booleans,
    그리고 없음.

예를 들면 다음과 같습니다.

>>> eval("shutil.rmtree('mongo')")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
  File "/opt/Python-2.6.1/lib/python2.6/shutil.py", line 208, in rmtree
    onerror(os.listdir, path, sys.exc_info())
  File "/opt/Python-2.6.1/lib/python2.6/shutil.py", line 206, in rmtree
    names = os.listdir(path)
OSError: [Errno 2] No such file or directory: 'mongo'
>>> ast.literal_eval("shutil.rmtree('mongo')")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/Python-2.6.1/lib/python2.6/ast.py", line 68, in literal_eval
    return _convert(node_or_string)
  File "/opt/Python-2.6.1/lib/python2.6/ast.py", line 67, in _convert
    raise ValueError('malformed string')
ValueError: malformed string

ast.literal_eval과 함께 사용하려면 문자열을 삭제해야한다고 덧붙여 야합니다. (따옴표 / 문자열에 큰 따옴표를 보장 이스케이프)
파울로 마토스에게

이 오류가 발생합니다 .Windows 7 x64에서 Python 2.6 (x86)에 있습니다. x64 파일 "D : \ Python26 \ lib \ ast.py", 48 행, literal_eval node_or_string = parse (node_or_string, mode = 'eval') 파일 "D 유효하지 않은 구문 : \ Python26 \ lib 디렉토리 \ ast.py "구문 분석 반환 컴파일에서, 라인 (36), (EXPR, 파일 이름, 모드, PyCF_ONLY_AST) 파일"<알 수없는> "라인 1 ^ 구문 에러

무엇에 대한 "dict(a=1)"스타일의 문자열?
n611x007

사전 내부의 열거 형 값에는 작동하지 않는 것 같습니다. 예 : d = "{ 'col': <Colors.RED : 2>, 'val': 2}"
shivshnkr

3
왜 json.dumps와 json.loads를 insead를 사용하지 않는가, 나는이 솔루션이 eval을 사용하는 것보다 더 선동적인 것을 발견했다
Auros132

232

https://docs.python.org/3.8/library/json.html

JSON은 디코더가 키와 값 주위에 큰 따옴표를 원하지만이 문제를 해결할 수 있습니다. 교체 해킹이 마음에 들지 않으면 ...

import json
s = "{'muffin' : 'lolz', 'foo' : 'kitty'}"
json_acceptable_string = s.replace("'", "\"")
d = json.loads(json_acceptable_string)
# d = {u'muffin': u'lolz', u'foo': u'kitty'}

키 또는 값의 일부로 작은 따옴표가 있으면 문자를 잘못 교체하면 실패합니다. 이 솔루션은 평가 솔루션에 대한 강력한 혐오가있는 경우에만 권장됩니다.

json 작은 따옴표에 대한 추가 정보 : jQuery.parseJSON은 JSON에서 작은 따옴표를 이스케이프하여 "잘못된 JSON"오류를 발생시킵니다.


12
{"foo": "b'ar"}
Mark E. Haase

4
{'foo': (1, 2, 3)}
Mark E. Haase

1
이 솔루션을 찾고있었습니다. +1디코더가 키와 값 주위에 큰 따옴표를 원한다는 것을 알려줍니다.
h8pathak

또 다른 문제는입니다 "{0: 'Hello'}".
Finn Årup Nielsen

3
쉼표 (JSON 호환이 아님)가있는 경우에도 실패합니다. 예 : "{ 'muffin': 'lolz', 'foo': 'kitty',}"
guival

159

사용하여 json.loads:

>>> import json
>>> h = '{"foo":"bar", "foo2":"bar2"}'
>>> d = json.loads(h)
>>> d
{u'foo': u'bar', u'foo2': u'bar2'}
>>> type(d)
<type 'dict'>

13
나는 그것이 OP의 대답에 대답한다고 생각하지 않습니다. json.laads를 사용하여 문자열 s = "{ 'muffin': 'lolz', 'foo': 'kitty'}"를 dict로 변환하는 방법은 무엇입니까?
technazi

왜 출력에 'u'가 인쇄됩니까? 예를 들어-str = '{ "1": "P", "2": "N", "3": "M"}'d = json.loads (str) print d 출력은 다음과 같습니다. {u'1 ': u'P ', u'3': u'M ', u'2': u'N '}
user905

2
@technazi : json.loads (h.replace ( " '",' " '))
ntg

그러나 다음과 같은 제한이 있습니다. 예 : h = '{ "muffin": "lolz", "foo": "kitty",}', h = '{ "muffin 's": "lolz", "foo": "kitty "} ', (유사한 답변에서 동일한 주석의 일부를 발견했습니다 ... 여전히 완전성을 위해 여기에 남아 있습니다 ...)
ntg

4
제 생각에는 그것이 가장 짧고 쉬운 방법입니다 ... 확실히 개인적으로 선호하는 방법입니다.
nostradamus

35

OP의 예를 들면 다음과 같습니다.

s = "{'muffin' : 'lolz', 'foo' : 'kitty'}"

Yaml 을 사용 하여 문자열에서 이런 종류의 비표준 json을 처리 할 수 있습니다 .

>>> import yaml
>>> s = "{'muffin' : 'lolz', 'foo' : 'kitty'}"
>>> s
"{'muffin' : 'lolz', 'foo' : 'kitty'}"
>>> yaml.load(s)
{'muffin': 'lolz', 'foo': 'kitty'}

1
이렇게하면 'yes'와 'no'문자열이 True / False로 변환됩니다.
Eric Marcos

23

문자열을 항상 신뢰할 수 있다면 사용 eval하거나 literal_eval제안 된대로 사용할 수 있습니다 ( 문자열이 무엇이든 안전합니다). 그렇지 않으면 파서가 필요합니다. JSON 구문 분석기 (예 : simplejson)는 JSON 체계에 맞는 컨텐츠 만 저장하는 경우 작동합니다.


8
2.6부터 simplejson은 Python 표준 라이브러리에 json 모듈로 포함되어 있습니다.
Eli Courtwright

11
예, 좋은 대답이지만 공식적으로 JSON은 원래 포스터의 예에서 주어진 것처럼 작은 따옴표로 묶인 문자열을 지원하지 않습니다.
Ben Hoyt 2016 년

19

사용하십시오 json. ast라이브러리는 많은 메모리와 느린을 소모합니다. 156Mb의 텍스트 파일을 읽어야하는 프로세스가 있습니다. Ast변환 사전에 5 분 지연, json60 % 적은 메모리 사용으로 1 분!


13
그러나 한계가 있습니다 : "{ 'foo': 'bar',}"문자열을 변환 해보십시오
ntg

12

요약:

import ast, yaml, json, timeit

descs=['short string','long string']
strings=['{"809001":2,"848545":2,"565828":1}','{"2979":1,"30581":1,"7296":1,"127256":1,"18803":2,"41619":1,"41312":1,"16837":1,"7253":1,"70075":1,"3453":1,"4126":1,"23599":1,"11465":3,"19172":1,"4019":1,"4775":1,"64225":1,"3235":2,"15593":1,"7528":1,"176840":1,"40022":1,"152854":1,"9878":1,"16156":1,"6512":1,"4138":1,"11090":1,"12259":1,"4934":1,"65581":1,"9747":2,"18290":1,"107981":1,"459762":1,"23177":1,"23246":1,"3591":1,"3671":1,"5767":1,"3930":1,"89507":2,"19293":1,"92797":1,"32444":2,"70089":1,"46549":1,"30988":1,"4613":1,"14042":1,"26298":1,"222972":1,"2982":1,"3932":1,"11134":1,"3084":1,"6516":1,"486617":1,"14475":2,"2127":1,"51359":1,"2662":1,"4121":1,"53848":2,"552967":1,"204081":1,"5675":2,"32433":1,"92448":1}']
funcs=[json.loads,eval,ast.literal_eval,yaml.load]

for  desc,string in zip(descs,strings):
    print('***',desc,'***')
    print('')
    for  func in funcs:
        print(func.__module__+' '+func.__name__+':')
        %timeit func(string)        
    print('')

결과 :

*** short string ***

json loads:
4.47 µs ± 33.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
builtins eval:
24.1 µs ± 163 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
ast literal_eval:
30.4 µs ± 299 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
yaml load:
504 µs ± 1.29 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

*** long string ***

json loads:
29.6 µs ± 230 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
builtins eval:
219 µs ± 3.92 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
ast literal_eval:
331 µs ± 1.89 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
yaml load:
9.02 ms ± 92.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

결론 : json.loads를 선호 하십시오.


5
이것을 제외하고는 그의 초기 문제의 일부인 작은 따옴표로 묶인 문자열로 작동하지 않습니다. 성능은 언급되지 않았습니다.
Michael Campbell

1
와우 .... 슈퍼 설명 ....
헤로인 체리

5
string = "{'server1':'value','server2':'value'}"

#Now removing { and }
s = string.replace("{" ,"")
finalstring = s.replace("}" , "")

#Splitting the string based on , we get key value pairs
list = finalstring.split(",")

dictionary ={}
for i in list:
    #Get Key Value pairs separately to store in dictionary
    keyvalue = i.split(":")

    #Replacing the single quotes in the leading.
    m= keyvalue[0].strip('\'')
    m = m.replace("\"", "")
    dictionary[m] = keyvalue[1].strip('"\'')

print dictionary

3
이 접근법에는 많은 실수가 있습니다. 어떤 키의 값이 포함되어있는 경우 {}. 어떤이 중첩 된 경우 dict. 값에 포함 된 경우 ,??
Om Sao

4

어떤 라이브러리도 사용되지 않습니다 :

dict_format_string = "{'1':'one', '2' : 'two'}"
d = {}
elems  = filter(str.isalnum,dict_format_string.split("'"))
values = elems[1::2]
keys   = elems[0::2]
d.update(zip(keys,values))

참고 : 하드 코드 된 것처럼 split("'")데이터가 "한 따옴표로 묶인"문자열에서만 작동합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.