Chuyển đổi một đại diện chuỗi của một từ điển thành một từ điển?


768

Làm thế nào tôi có thể chuyển đổi strbiểu diễn của a dict, chẳng hạn như chuỗi sau, thành một dict?

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

Tôi không thích sử dụng eval. Tôi có thể sử dụng cái gì khác?

Lý do chính cho điều này, là một trong những lớp đồng nghiệp của tôi, ông đã viết, chuyển đổi tất cả đầu vào thành chuỗi. Tôi không có tâm trạng để đi và sửa đổi các lớp học của mình, để giải quyết vấn đề này.


1
Nếu bạn không thể sử dụng Python 2.6, bạn có thể sử dụng một hàm ẩn an toàn đơn giản như code.activestate.com/recipes/364469 Nó cõng trên trình biên dịch Python để bạn không phải tự mình làm tất cả công việc.
Ned Batchelder

11
Lưu ý : Đối với những người đến đây với dữ liệu JSON trông tương tự nhau , bạn muốn đọc Parse JSON trong Python thay thế. JSON không giống với Python . Nếu bạn có dấu ngoặc kép quanh chuỗi của mình, bạn có thể có dữ liệu JSON. Bạn cũng có thể tìm kiếm , hoặc , sử dụng Python cú pháp , và . "nulltruefalseNoneTrueFalse
Martijn Pieters

Câu trả lời:


1167

Bắt đầu trong Python 2.6, bạn có thể sử dụng tích hợp ast.literal_eval:

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

Điều này là an toàn hơn so với sử dụng eval. Như tài liệu của chính nó nói:

>>> trợ giúp (ast.literal_eval)
Trợ giúp về chức năng lítal_eval trong mô-đun ast:

lítal_eval (node_or_opes)
    Đánh giá an toàn một nút biểu thức hoặc một chuỗi chứa Python
    biểu hiện. Chuỗi hoặc nút được cung cấp chỉ có thể bao gồm những điều sau đây
    Cấu trúc nghĩa đen của Python: chuỗi, số, bộ dữ liệu, danh sách, dicts, booleans,
    và Không có.

Ví dụ:

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

Tôi nên thêm rằng bạn cần vệ sinh chuỗi để sử dụng với ast.literal_eval. (đảm bảo dấu ngoặc kép / dấu ngoặc kép trong chuỗi được thoát)
Paulo Matos

Tôi gặp lỗi này Tôi đang dùng python 2.6 (x86) trên windows 7 x64 Tệp "D: \ Python26 \ lib \ ast.py", dòng 48, trong lítal_eval node_or_opes = parse (node_or_opes, mode = 'eval') Tệp "D : \ Python26 \ lib \ ast.py ", dòng 36, trong biên dịch trả lại phân tích cú pháp (expr, tên tệp, chế độ, PyCF_ONLY_AST) Tệp" <unknown> ", dòng 1 ^ SyntaxError: cú pháp không hợp lệ

những gì về "dict(a=1)"chuỗi phong cách?
n611x007

Điều này dường như không hoạt động cho giá trị enum trong một từ điển. Ví dụ: d = "{'col': <Colors.RED: 2>, 'val': 2}"
shivshnkr

3
Tại sao không sử dụng json.dumps và json.loads, tôi thấy giải pháp này cao hơn bằng cách sử dụng eval
Auros132

232

https://docs.python.org/3.8/l Library / json.html

JSON có thể giải quyết vấn đề này mặc dù bộ giải mã của nó muốn có dấu ngoặc kép quanh các khóa và giá trị. Nếu bạn không phiền một hack thay thế ...

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

LƯU Ý rằng nếu bạn có dấu ngoặc đơn là một phần của khóa hoặc giá trị thì điều này sẽ không thành công do thay thế ký tự không đúng. Giải pháp này chỉ được khuyến nghị nếu bạn có ác cảm mạnh mẽ với giải pháp eval.

Thông tin thêm về json trích dẫn đơn: jQuery.parseJSON ném ra Lỗi JSON JSON không hợp lệ do thoát trích dẫn đơn trong JSON


12
{"foo": "b'ar"}
Đánh dấu E. Haase

4
{'foo': (1, 2, 3)}
Đánh dấu E. Haase

1
Tôi đã tìm kiếm giải pháp này. +1để thông báo rằng bộ giải mã muốn báo giá kép xung quanh các khóa và giá trị.
h8pathak

Một vấn đề khác là cho "{0: 'Hello'}".
Finn Årup Nielsen

3
Điều này cũng không thành công nếu bạn có dấu phẩy (không tuân thủ JSON), ví dụ: "{'muffin': 'lolz', 'foo': 'kitty',}"
guival 21/03/18

159

sử dụng 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
Tôi không nghĩ nó trả lời câu trả lời của OP. Làm cách nào để chúng tôi sử dụng json.laads để chuyển đổi một chuỗi s = "{'muffin': 'lolz', 'foo': 'kitty'}" thành dict?
Technazi

Tại sao in này 'u' trong đầu ra ?? ví dụ: str = '{"1": "P", "2": "N", "3": "M"}' d = json.loads (str) in d đầu ra là: {u'1 ': u'P ', u'3': u'M ', u'2': u'N '}
user905

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

Tuy nhiên, có các giới hạn, ví dụ: h = '{"muffin": "lolz", "foo": "kitty",}', cũng h = '{"muffin": "lolz", "foo": "kitty "} ', (chỉ nhận thấy một phần của các bình luận tương tự trong một câu trả lời tương tự ... vẫn còn ở đây cho đầy đủ ...)
ntg

4
Theo tôi, đó là cách ngắn nhất và dễ nhất ... Chắc chắn là cách tôi thích nhất.
lỗ mũi

35

Ví dụ của OP:

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

Chúng ta có thể sử dụng Yaml để đối phó với loại json không chuẩn này trong chuỗi:

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

1
Điều này sẽ khiến các chuỗi 'có' và 'không' được chuyển đổi thành Đúng / Sai
Eric Marcos

23

Nếu chuỗi luôn có thể tin cậy, bạn có thể sử dụng eval(hoặc sử dụng literal_evalnhư được đề xuất; nó an toàn cho dù chuỗi đó là gì.) Nếu không, bạn cần một trình phân tích cú pháp. Trình phân tích cú pháp JSON (chẳng hạn như Simplejson) sẽ hoạt động nếu anh ta chỉ lưu trữ nội dung phù hợp với lược đồ JSON.


8
Bắt đầu từ 2.6, Simplejson được bao gồm trong thư viện chuẩn Python dưới dạng mô đun json.
Eli Courtwright

11
Vâng, đó là một câu trả lời hay, nhưng lưu ý rằng JSON chính thức không hỗ trợ các chuỗi trích dẫn đơn, như được đưa ra trong ví dụ của người đăng bài gốc.
Ben Hoyt

19

Sử dụng json. các astthư viện tiêu tốn rất nhiều bộ nhớ và và chậm hơn. Tôi có một quy trình cần đọc tệp văn bản 156Mb. Astvới độ trễ 5 phút cho từ điển chuyển đổi jsonvà 1 phút sử dụng bộ nhớ ít hơn 60%!


13
nhưng có giới hạn của nó: thử chuyển đổi chuỗi "{'foo': 'bar',}"
ntg

12

Để tóm tắt:

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('')

Các kết quả:

*** 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)

Kết luận: thích json.loads


5
Ngoại trừ điều này sẽ không hoạt động với chuỗi trích dẫn đơn của anh ấy, đó là một phần của vấn đề ban đầu của anh ấy. Hiệu suất không bao giờ được đề cập.
Michael Campbell

1
Wow .... Siêu giải thích ....
smack cherry

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
Nhiều sai lầm trong cách tiếp cận này. Điều gì nếu giá trị của một khóa chứa {hoặc }. Nếu nó được lồng nhau dict. Nếu giá trị chứa ,??
Om Sao

4

không có lib nào được sử dụng:

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))

LƯU Ý: Vì nó đã được mã hóa cứng split("'")sẽ chỉ hoạt động đối với các chuỗi trong đó dữ liệu là "trích dẫn đơn".

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.