1

I have a very long string, that looks like a dictionary, but where many of the keys have been replaced by variables that are undefined, e.g.:

dict_1_str = '{a: "date", b: 7, c: {d: 5, e: "Hello There!"}}'

In an actual dictionary, I have the variable names and values.

dict_2 = {"a": 1, "b": 2, "c": 3, "d": "General Kenobi!", "e": 5}

I want to update the keys in the top dictionary with the values in the bottom dictionary. I thought I could create a list of dict_2's keys and a list of dict_2's values, and then use exec() to evaluate the lists as equal, and so set all the variables in one go — but I cannot get it to work, and I would rather avoid exec() if I can.

I tried to use regex, but many of string values in dict_1_str contain the names of the keys/variables. Is there some elegant way of doing this?

martineau
  • 119,623
  • 25
  • 170
  • 301

3 Answers3

1

It would be slightly less unsafe than using exec(), but you can use eval() and pass it a globals dictionary argument that would prevent any Python built-ins from being used by the expression being passed to evaluate. (Your dict_2 would be the locals argument.)

import json

dict_1_str = '{a: "date", b: 7, c: {d: 5, e: "Hello There!"}}'
dict_2 = {"a": 1, "b": 2, "c": 3, "d": "General Kenobi!", "e": 5}

result = eval(dict_1_str, {'__builtins__': None}, dict_2)
print(json.dumps(result))

Output:

{"1": "date", "2": 7, "3": {"General Kenobi!": 5, "5": "Hello There!"}}
martineau
  • 119,623
  • 25
  • 170
  • 301
  • Yeah this worked nicely, thanks. I was close, just didn't quite understand how to use the locals argument . – Ben Wilkinson Feb 27 '21 at 03:22
  • Note that using the _`locals`_ argument isn't a requirement. `eval(dict_1_str, dict({'__builtins__': None}, **dict_2))` would also work fine but is a little harder to understand (as well as write). – martineau Feb 27 '21 at 07:27
0

Does this module demjson helps?

pip install demjson

You can try with below codes for your reference.

import demjson

dict_1_str = '{a: "date", b: 7, c: {d: 5, e: "Hello There!"}}'
dict_2 = {"a": 1, "b": 2, "c": 3, "d": "General Kenobi!", "e": 5}

s = demjson.decode(dict_1_str)
s.update(dict_2)
print(s)
# {'a': 1, 'b': 2, 'c': 3, 'd': 'General Kenobi!', 'e': 5}

r = demjson.encode(s)
print(r)
# {"a":1,"b":2,"c":3,"d":"General Kenobi!","e":5}

jia Jimmy
  • 1,693
  • 2
  • 18
  • 38
  • I had a go at this. it turns out some of the values in the dict1_str are also unquoted, and I think this method failed because of that, which was not in the original question. But I think it does work when only the keys need to be replaced. Thanks – Ben Wilkinson Feb 27 '21 at 03:27
0
import json 

# first I added quotes to surround property names in the string
dict_1_str = '{"a": "date", "b": 7, "c": {"d": 5, "e": "Hello There!"}}'
dict_2 = {"a": 1, "b": 2, "c": 3, "d": "General Kenobi!", "e": 5}

# This will convert the string to a dict
dict_1 = json.loads(dict_1_str)

# Here is a solution to merge two dict
dict_3 = {**dict_1, **dict_2}

Here you can read more on How do I merge two dictionaries in a single expression in Python (taking union of dictionaries)?

AlexisG
  • 2,476
  • 3
  • 11
  • 25