有如下字符串:
'{"name" : "apollo_miracle", "gender" : "male", "age": 18}'
想转化为字典格式:
{'name': 'apollo_miracle', 'gender': 'male', 'age': 18}
In [1]: import json
In [2]: user_info = '{"name" : "apollo_miracle", "gender" : "male", "age": 18}'
In [3]: user_dict = json.loads(user_info)
In [4]: user_dict
Out[4]: {'name': 'apollo_miracle', 'gender': 'male', 'age': 18}
但是使用 json
进行转换存在一个潜在的问题。
由于 json
语法规定 数组或对象之中的字符串必须使用双引号,不能使用单引号 ,因此下面的转换是错误的:
In [5]: user_info_02 = "{'name' : 'apollo_miracle', 'gender' : 'male', 'age': 18}"
In [6]: user_dict_02 = json.loads(user_info_02)
---------------------------------------------------------------------------
JSONDecodeError Traceback (most recent call last)
in
----> 1 user_dict_02 = json.loads(user_info_02)
d:\python\python36\lib\json\__init__.py in loads(s, encoding, cls, object_hook, parse_float, parse_int, parse_constant, object_pa
irs_hook, **kw)
352 parse_int is None and parse_float is None and
353 parse_constant is None and object_pairs_hook is None and not kw):
--> 354 return _default_decoder.decode(s)
355 if cls is None:
356 cls = JSONDecoder
d:\python\python36\lib\json\decoder.py in decode(self, s, _w)
337
338 """
--> 339 obj, end = self.raw_decode(s, idx=_w(s, 0).end())
340 end = _w(s, end).end()
341 if end != len(s):
d:\python\python36\lib\json\decoder.py in raw_decode(self, s, idx)
353 """
354 try:
--> 355 obj, end = self.scan_once(s, idx)
356 except StopIteration as err:
357 raise JSONDecodeError("Expecting value", s, err.value) from None
JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
解决方案:将字符串中的单引号改为双引号。
定义如下函数:
import json
import re
def str_2_dict(my_str):
try:
my_dict = json.loads(my_str)
except json.JSONDecodeError:
my_str = re.sub(r"'", '"', my_str)
my_dict = json.loads(my_str)
return my_dict
再次进行转换,没有问题
In [7]: import json
...: import re
...:
...: def str_2_dict(my_str):
...: try:
...: my_dict = json.loads(my_str)
...: except json.JSONDecodeError:
...: my_str = re.sub(r"'", '"', my_str)
...: my_dict = json.loads(my_str)
...:
...: return my_dict
...:
In [8]: user_dict = str_2_dict(user_info)
In [9]: user_dict_02 = str_2_dict(user_info_02)
In [10]: user_dict
Out[10]: {'name': 'apollo_miracle', 'gender': 'male', 'age': 18}
In [11]: user_dict_02
Out[11]: {'name': 'apollo_miracle', 'gender': 'male', 'age': 18}
In [12]: user_dict = eval(user_info)
In [13]: user_dict
Out[13]: {'name': 'apollo_miracle', 'gender': 'male', 'age': 18}
In [14]: user_dict_02 = eval(user_info_02)
In [15]: user_dict_02
Out[15]: {'name': 'apollo_miracle', 'gender': 'male', 'age': 18}
通过
eval
进行转换就不存在上面使用json
进行转换的问题。但是,使用eval
却存在安全性的问题
比如下面的例子:
In [16]: user_info = input("输入用户信息:")
输入用户信息:__import__('os').system('dir')
In [17]: user_dict = eval(user_info)
驱动器 G 中的卷是 工作
卷的序列号是 C65E-5C90
... 此处省略一万字 ...
如果再输入一些删除命令,则可以把整个目录清空了!后果不敢想象。。。
In [18]: import ast
In [19]: user_info = '{"name" : "apollo_miracle", "gender" : "male", "age": 18}'
...: user_info_02 = "{'name' : 'apollo_miracle', 'gender' : 'male', 'age': 18}"
In [20]: user_dict = ast.literal_eval(user_info)
In [21]: user_dict
Out[21]: {'name': 'apollo_miracle', 'gender': 'male', 'age': 18}
In [22]: user_dict_02 = ast.literal_eval(user_info_02)
In [23]: user_dict_02
Out[23]: {'name': 'apollo_miracle', 'gender': 'male', 'age': 18}
In [24]: user_info = input("输入用户信息:")
输入用户信息:__import__('os').system('dir')
In [25]: user_info = ast.literal_eval(user_info)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
in
----> 1 user_info = ast.literal_eval(user_info)
d:\python\python36\lib\ast.py in literal_eval(node_or_string)
83 return left - right
84 raise ValueError('malformed node or string: ' + repr(node))
---> 85 return _convert(node_or_string)
86
87
d:\python\python36\lib\ast.py in _convert(node)
82 else:
83 return left - right
---> 84 raise ValueError('malformed node or string: ' + repr(node))
85 return _convert(node_or_string)
86
ValueError: malformed node or string: <_ast.Call object at 0x0000019F3B9BEE10>
使用
ast.literal_eval
进行转换既不存在使用json
进行转换的问题,也不存在使用eval
进行转换的安全性问题
,因此推荐使用ast.literal_eval
。