I have string values as,
\"a\"
\"a.b\"
\"b.c.d\"
How to convert them into python dictionary variables as,
a
a[\"b\"]
b[\"c\"][\
eval
is fairly dangerous here, since this is untrusted input. You could use regex to grab the dict name and key names and look them up using vars
and dict.get
.
import re
a = {'b': {'c': True}}
in_ = 'a.b.c'
match = re.match(
r"""(?P<dict> # begin named group 'dict'
[^.]+ # one or more non-period characters
) # end named group 'dict'
\. # a literal dot
(?P<keys> # begin named group 'keys'
.* # the rest of the string!
) # end named group 'keys'""",
in_,
flags=re.X)
d = vars()[match.group('dict')]
for key in match.group('keys'):
d = d.get(key, None)
if d is None:
# handle the case where the dict doesn't have that (sub)key!
print("Uh oh!")
break
result = d
# result == True
Or even more simply: split on dots.
in_ = 'a.b.c'
input_split = in_.split('.')
d_name, keys = input_split[0], input_split[1:]
d = vars()[d_name]
for key in keys:
d = d.get(key, None)
if d is None:
# same as above
result = d
The pyjq library does something quite similar to this, except you have to explicitly provide a dictionary to be the root, and you have to prefix your strings with a .
to refer to whatever dictionary was your root.
python:
import pyjq
d = { 'a' : { 'b' : { 'c' : 'd' } } }
for path in ['.a', '.a.b', '.b.c.d', '.x']:
print(pyjq.first(path, d))
output:
{'b': {'c': 'd'}}
{'c': 'd'}
None
None
I ran into this same problem for parsing ini files with dot-delimited keys in different sections. e.g.:
[app]
site1.ftp.host = hostname
site1.ftp.username = username
site1.database.hostname = db_host
; etc..
So I wrote a little function to add "add_branch" to an existing dict tree:
def add_branch(tree, vector, value):
"""
Given a dict, a vector, and a value, insert the value into the dict
at the tree leaf specified by the vector. Recursive!
Params:
data (dict): The data structure to insert the vector into.
vector (list): A list of values representing the path to the leaf node.
value (object): The object to be inserted at the leaf
Example 1:
tree = {'a': 'apple'}
vector = ['b', 'c', 'd']
value = 'dog'
tree = add_branch(tree, vector, value)
Returns:
tree = { 'a': 'apple', 'b': { 'c': {'d': 'dog'}}}
Example 2:
vector2 = ['b', 'c', 'e']
value2 = 'egg'
tree = add_branch(tree, vector2, value2)
Returns:
tree = { 'a': 'apple', 'b': { 'c': {'d': 'dog', 'e': 'egg'}}}
Returns:
dict: The dict with the value placed at the path specified.
Algorithm:
If we're at the leaf, add it as key/value to the tree
Else: If the subtree doesn't exist, create it.
Recurse with the subtree and the left shifted vector.
Return the tree.
"""
key = vector[0]
tree[key] = value \
if len(vector) == 1 \
else add_branch(tree[key] if key in tree else {},
vector[1:],
value)
return tree
s = "a.b.c"
s = s.replace(".", "][")+"]" # 'a][b][c]'
i = s.find("]") # find the first "]"
s = s[:i]+s[i+1:] # remove it 'a[b][c]'
s = s.replace("]", "\"]").replace("[", "[\"") # add quotations 'a["b"]["c"]'
# you can now execute it:
v = eval(s)