String containing list and other data types to dictionary without changing the data type in python
Clash Royale CLAN TAG#URR8PPP
String containing list and other data types to dictionary without changing the data type in python
I have one string as below:
key_val = "count=2, name=['hello', 'hi'], word='Dial::100', roll=12"
I need to get the dictionary from the string as below:
d_key_val = 'count'=2, 'name'=['hello', 'hi'], 'word'='Dial::100', 'roll'=12
I tried with the following:
regx = r'(?P<key>w+)=(?P<value>[.+?]|d+|S+)'
r_key_val = re_findall(regx, key_val)
for key, value in r_key_val:
d_key_val[key] = value
But it is storing values as all string:
d_key_val = 'count'='2', 'name'="['hello', 'hi']", 'word'="'Dial::100'", 'roll'='12'
Is there any way or regex to store the values as same data type as it has in string?
2 Answers
2
If you are 100% sure that the data is "safe", you could eval
it as the parameters to dict
:
eval
dict
>>> key_val = "count=2, name=['hello', 'hi'], word='Dial::100', roll=12"
>>> eval("dict(%s)" % key_val)
'count': 2, 'name': ['hello', 'hi'], 'roll': 12, 'word': 'Dial::100'
If you are not sure, better don't use eval
, though.
eval
Alternatively, you could use your regex and use ast.literal_eval
to evaluate the value
:
ast.literal_eval
value
>>> regx = r'(?P<key>w+)=(?P<value>[.+?]|d+|S+)'
>>> k: ast.literal_eval(v) for k, v in re.findall(regx, key_val)
'count': 2, 'name': ['hello', 'hi'], 'roll': 12, 'word': ('Dial::100',)
(Note: I did not check your regex in detail.) You could also try to apply ast.literal_eval
to the entire expression, instead of the less safe eval
, but this would require some preprocessing, e.g. replacing =
with :
and adding quotes to the keys, that might not work well with e.g. string values containing those symbols.
ast.literal_eval
eval
=
:
regex
cannot do that, but you can! You can write a function like the following that takes the values
regex
writes out and converts them to the appropriate type.
regex
values
regex
def type_converter(v):
if v[0] == '[' and v[-1] == ']':
v = v.replace('[', '').replace(']', '')
return [type_converter(x) for x in v.split(',')]
try:
v = int(v)
except ValueError:
try:
v = float(v)
except ValueError:
pass
finally:
return v
To add this to your code, simply do:
regx = r'(?P<key>w+)=(?P<value>[.+?]|d+|S+)'
r_key_val = re_findall(regx, key_val)
for key, value in r_key_val:
d_key_val[key] = type_converter(value) # <- this
Example:
lst = ['2', '1.2' ,'foo', '[1, 2]']
print([type(type_converter(x)) for x in lst ])
# [<class 'int'>, <class 'float'>, <class 'str'>, <class 'list'>]
Note that the order in which the try
-blocks are written is very important since float('1')
does not raise any Errors but the correct type is int
!
try
float('1')
int
More difficult for the
list
part, though. Maybe use ast.literal_eval
instead?– tobias_k
Aug 8 at 11:20
list
ast.literal_eval
@tobias_k I noticed that later but I updated the fuction to a recursive one to handle that. At the end of the day,
ast.literal_eval
or some fancy json
command might be much handier.– Ev. Kounis
Aug 8 at 11:26
ast.literal_eval
json
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Related: Simple way to convert a string to a dictionary
– jpp
Aug 8 at 15:05