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


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.