辞書の文字列表現を辞書に変換しますか?


768

次の文字列などののstr表現をどのように変換できますか?dictdict

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

使用したくないeval。他に何が使えますか?

これの主な理由は、彼が書いた私の同僚クラスの1つであり、すべての入力を文字列に変換します。私はこの問題に対処するために、彼のクラスに行って修正する気分ではありません。


1
Python 2.6を使用できない場合は、code.activestate.com / recipes / 364469のような単純なsafeeval実装を使用できます。Pythonコンパイラーに便乗するため、大まかな作業をすべて自分で行う必要はありません。
Ned Batchelder、

11
見かけが似ている JSONデータがここにある場合は、代わりにPythonでParse JSONを読んでください。JSONはPythonと同じではありません。あなたが持っている場合は"、あなたの文字列を二重引用符を、あなたは、おそらくJSONデータを持っています。あなたはまたのために見ることができるnulltrueまたはfalse、Pythonの構文の使用NoneTrueおよびFalse
Martijn Pieters

回答:


1167

Python 2.6以降では、組み込みを使用できますast.literal_eval

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

これはを使用するよりも安全ですeval。それ自身のドキュメントが言うように:

>>>ヘルプ(ast.literal_eval)
モジュールastの関数literal_evalに関するヘルプ:

literal_eval(node_or_string)
    式ノードまたはPythonを含む文字列を安全に評価する
    式。提供される文字列またはノードは、次のもののみで構成されます
    Pythonリテラル構造:文字列、数値、タプル、リスト、辞書、ブール値、
    なし。

例えば:

>>> 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で使用するために文字列をサニタイズする必要があることを付け加えておきます。(文字列内の引用符/二重引用符がエスケープされていることを確認してください)
Paulo Matos

私はこのエラーを受け取りました。Windows7 x64のpython 2.6(x86)にいます:\ Python26 \ lib \ ast.py "、36行目、parse return compile(expr、filename、mode、PyCF_ONLY_AST)File" <unknown> "、line 1 ^

何についての"dict(a=1)"スタイルの文字列?
n611x007 14

これは、辞書内の列挙値では機能しないようです。例:d = "{'col':<Colors.RED:2>、 'val':2}"
shivshnkr

3
なぜjson.dumpsとjson.loadsを使用しないでください。このソリューションは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の単一引用符の詳細:JSONで単一引用符がエスケープされているため、jQuery.parseJSONが「無効なJSON」エラーをスローする


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

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

1
私はこの解決策を探していました。 +1デコーダーがキーと値を二重引用符で囲む必要があることを通知するため。
h8pathak 2017

別の問題はです"{0: 'Hello'}"
FinnÅrupNielsen 2017

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'}"をディクテーションに変換するにはどうすればよいですか?
テクナジ2016年

なぜこの出力に「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 2017年

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
これにより、「はい」と「いいえ」の文字列がTrue / Falseに変換されます
Eric Marcos

23

文字列が常に信頼できる場合は、使用することができますeval(またはliteral_eval推奨どおりに使用します。文字列が何であっても安全です)。それ以外の場合は、パーサーが必要です。JSONパーサー(simplejsonなど)は、JSONスキームに適合するコンテンツのみを保存する場合にのみ機能します。


8
2.6以降、simplejsonはPython標準ライブラリにjsonモジュールとして含まれています。
Eli Courtwright、2009年

11
ええ、それは良い答えですが、元の投稿者の例にあるように、公式にJSONは単一引用符で囲まれた文字列をサポートしていないことに注意してください。
ベンホイト

19

を使用しjsonます。astライブラリは、多くのメモリを消費し、より遅いです。156Mbのテキストファイルを読み取る必要があるプロセスがあります。Ast変換辞書の遅延は5分、jsonメモリの使用量は60%削減された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
これは、彼の最初の問題の一部であった一重引用符付きの文字列では機能しません。パフォーマンスについては言及されていません。
マイケルキャンベル

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

libは使用されません。

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.