当前位置:网站首页>json数据比较器
json数据比较器
2022-07-01 05:28:00 【hotswwkyo】
json数据比较器
不仅支持对json对象、数组的直接比较,还支持嵌套的复杂json对象和数组的直接比较。
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
''' @Author: 思文伟 '''
import json
class JSONCheckpoint(object):
"""JSON格式数据检查点,支持两个复杂JSON直接比较 JSON 数据写为名称/值对。 名称/值由字段名称构成,后跟冒号和值:{ "name":"Bill Gates" } 在 JSON 中,值必须是以下数据类型之一: 字符串 数字 对象(JSON 对象) 数组 布尔 null Simple usage: alist = [{ "status": "success", "data": { "44131521": [{ "joinno": "201812120000013935", "zzbcode": "44131521", }, { "joinno": "201812120000013936", "zzbcode": "44131521", }, { "joinno": "201812120000013937", "zzbcode": "44131521", }] } }] elist = [{ "status": "success", "data": { "44131521": [{ "joinno": "201812120000013937", "zzbcode": "44131521" }, { "joinno": "201812120000013935", "zzbcode": "44131521", }, { "joinno": "201812120000013936", "zzbcode": "44131521", }] } }] JSONCheckpoint().test(alist, elist, False) """
CONVERT_JSON_TEXT_TO_PYTHON_OBJECT = True
def to_py_obj(self, json_text):
return json.loads(json_text)
def test(self, actual, expected, convert=CONVERT_JSON_TEXT_TO_PYTHON_OBJECT, ignore_position=True, list_strict=True, dict_strict=True):
"""比较两个对象是否相等 Args: - actual: 实际 - expected: 预期 - ignore_position: 控制是调用忽略位置比较函数还是完全相等比较函数 True - 忽略位置 False - 完全相等 - list_strict: ignore_position为True的时候,该参数才有意义 - dict_strict: ignore_position为True的时候,该参数才有意义 """
if convert == self.CONVERT_JSON_TEXT_TO_PYTHON_OBJECT:
expected = self.to_py_obj(expected)
print(self.equals(actual, expected, ignore_position=ignore_position, list_strict=list_strict, dict_strict=dict_strict))
def equals(self, actual, expected, ignore_position=True, list_strict=True, dict_strict=True):
"""比较两个对象是否相等 Args: - actual: 实际 - expected: 预期 - ignore_position: 控制是调用忽略位置比较函数还是完全相等比较函数 True - 忽略位置 False - 完全相等 - list_strict: ignore_position为True的时候,该参数才有意义 - dict_strict: ignore_position为True的时候,该参数才有意义 """
if isinstance(expected, (list, tuple)) and isinstance(actual, (list, tuple)):
if ignore_position:
return self.json_array_equals_ignore_position(actual, expected, list_strict=list_strict, dict_strict=dict_strict)
else:
return self.json_array_equals(actual, expected)
elif isinstance(expected, dict) and isinstance(actual, dict):
if ignore_position:
return self.json_obj_equals_ignore_position(actual, expected, dict_strict=dict_strict, list_strict=list_strict)
else:
return self.json_obj_equals(actual, expected)
elif isinstance(expected, bool) or isinstance(actual, bool): # 任意一个是bool值,则进行bool值比较
return self.all_is_same_bool_value(actual, expected)
elif expected is None or actual is None: # 任意一个是None值,则进行None比较
return self.all_is_none(actual, expected)
else:
return actual == expected
def _group(self, dlist):
"""根据数据类型对列表的子元素分组,分组规则如下: - None 分为一组 - 布尔值 分为一组 - 字符串 整型 浮点型 分为一组 - 列表 元祖 分组一组 - 字典类型分为一组 - 除了上面之外的其他类型分为一组 """
others = []
sublists = []
subdicts = []
nonelist = []
boollist = []
str_int_float = []
for one in dlist:
if one is None:
nonelist.append(one)
elif isinstance(one, bool):
boollist.append(one)
elif isinstance(one, (str, int, float)):
str_int_float.append(one)
elif isinstance(one, (list, tuple)):
sublists.append(one)
elif isinstance(one, dict):
subdicts.append(one)
else:
others.append(one)
return nonelist, boollist, str_int_float, sublists, subdicts, others
def json_obj_equals_ignore_position(self, adict, edict, dict_strict=True, list_strict=True):
"""json对象类型数据相当于python的字典,比较两个字典是否相等,支持嵌套字典和列表元祖 Args: - adict 实际字典 - edict 预期字典 - dict_strict 布尔值,控制字典及其包含的嵌套字典的比较方式, True - 两个字典必须键和值完全一致才相等 False - 只要实际字典的包含有预期字典的键值就认为相等 - list_strict 布尔值,控制列表及其包含的嵌套列表的比较方式, True - 两个列表元素个数必须完全相等,同时元素都一样则认为两个列表相等 False - 只要实际列表包含有预期列表的元素就认为两个列表相等(相当于预期列表的元素是实际列表的元素的子集) Useage: self.json_obj_equals_ignore_position({"a":1,"b":2}, {"a":1,"b":2}) >>> True self.json_obj_equals_ignore_position({"a":1,"b":2}, {"a":1}, dict_strict=False) >>> True self.json_obj_equals_ignore_position({"a":1,"b":{"c":3}}, {"a":1,"b":{"c":3}}) >>> True """
akeys = adict.keys()
ekeys = edict.keys()
if dict_strict:
if len(akeys) != len(ekeys):
return False
for k in ekeys:
if k not in akeys:
return False
else:
v1 = adict[k]
v2 = edict[k]
if isinstance(v1, (list, tuple)) and isinstance(v2, (list, tuple)):
if not self.json_array_equals_ignore_position(v1, v2, list_strict=list_strict, dict_strict=dict_strict):
return False
elif isinstance(v1, dict) and isinstance(v2, dict):
subresult = self.json_obj_equals_ignore_position(v1, v2, dict_strict=dict_strict, list_strict=list_strict)
if not subresult:
return False
elif isinstance(v1, bool) or isinstance(v2, bool): # 任意一个是bool值,则进行bool值比较
if not self.all_is_same_bool_value(v1, v2):
return False
elif v1 is None or v2 is None: # 任意一个是None值,则进行None比较
if not self.all_is_none(v1, v2):
return False
else:
if v1 != v2:
return False
return True
def _none_equals(self, a_nonelist, e_nonelist, strict=True):
is_equals = True
if strict:
len1 = len(a_nonelist)
len2 = len(e_nonelist)
used = []
if len1 == len2:
for val in e_nonelist:
if val not in used:
used.append(val)
count1 = a_nonelist.count(val)
count2 = e_nonelist.count(val)
if count1 != count2:
is_equals = False
break
else:
is_equals = False
else:
foundindexs = []
for e_none in e_nonelist:
found = False
for i, a_none in enumerate(a_nonelist):
if i not in foundindexs:
if e_none is a_none:
foundindexs.append(i)
found = True
if not found:
is_equals = False
break
return is_equals
_bool_equals = _none_equals
def _basic_data_equals(self, a_data, e_data, strict=True):
is_equals = True
if strict:
used = []
len1 = len(a_data)
len2 = len(e_data)
if len1 == len2:
for val in a_data:
if val not in used:
used.append(val)
count1 = a_data.count(val)
count2 = e_data.count(val)
if count1 != count2:
is_equals = False
break
else:
is_equals = False
else:
found_indexs = []
for e_val in e_data:
found = False
for i, a_val in enumerate(a_data):
if i not in found_indexs:
if e_val == a_val:
found_indexs.append(i)
found = True
break
if not found:
is_equals = False
break
return is_equals
_unknow_type_data_equals = _basic_data_equals
@staticmethod
def is_all_empty_objs(*objs):
empty = True
for obj in objs:
if len(obj) >= 1:
empty = False
break
return empty
@staticmethod
def all_is_same_bool_value(*objs):
truelist = []
falselist = []
non_bool = False
for obj in objs:
if isinstance(obj, bool):
if obj is True:
truelist.append(obj)
else:
falselist.append(obj)
else:
non_bool = True
break
if non_bool:
return False # any object is not boolean
else:
if len(objs) == len(truelist) or len(objs) == len(falselist):
return True
else:
return False
@staticmethod
def all_is_none(*objs):
nonelist = []
for obj in objs:
if obj is None:
nonelist.append(obj)
else:
break
if len(nonelist) == len(objs):
return True
else:
return False
def _json_array_equals_ignore_position(self, source, expected, list_strict=True, dict_strict=True):
""" Args: - source 实际列表中所有是列表的子元素构成的列表 - expected 预期列表中所有是列表的子元素构成的列表 - list_strict 布尔值,控制列表及其包含的嵌套列表的比较方式, True - 两个列表元素个数必须完全相等,同时元素都一样则认为两个列表相等 False - 只要实际列表包含有预期列表的元素就认为两个列表相等(相当于预期列表的元素是实际列表的元素的子集) - dict_strict 布尔值,控制字典及其包含的嵌套字典的比较方式, True - 两个字典必须键和值完全一致才相等 False - 只要实际字典的包含有预期字典的键值就认为相等 """
len1 = len(source)
len2 = len(expected)
founds = []
for a_val in source:
a_len = len(a_val)
for e_val in expected:
e_len = len(e_val)
if a_len == e_len:
if self.json_array_equals_ignore_position(a_val, e_val, list_strict=list_strict, dict_strict=dict_strict):
founds.append(a_val)
break
flen = len(founds)
return (len1 == len2) and (len2 == flen)
def _dictlist_check(self, source, expected, list_strict=True, dict_strict=True):
""" Args: - source 实际列表中所有是字典的子元素构成的列表 - expected 预期列表中所有是字典的子元素构成的列表 - dict_strict 布尔值,控制字典及其包含的嵌套字典的比较方式, True - 两个字典必须键和值完全一致才相等 False - 只要实际字典的包含有预期字典的键值就认为相等 - list_strict 布尔值,控制列表及其包含的嵌套列表的比较方式, True - 两个列表元素个数必须完全相等,同时元素都一样则认为两个列表相等 False - 只要实际列表包含有预期列表的元素就认为两个列表相等(相当于预期列表的元素是实际列表的元素的子集) """
len1 = len(source)
len2 = len(expected)
if len1 == len2:
used_indexs = []
not_found_in_source = []
for edict in expected:
found = False
for index, sdict in enumerate(source):
if index in used_indexs:
continue
if self.json_obj_equals_ignore_position(sdict, edict, dict_strict=dict_strict, list_strict=list_strict):
found = True
used_indexs.append(index)
break
if not found:
not_found_in_source.append(edict)
break
if not_found_in_source:
return False
else:
return True
else:
return False
def printjson(self, *obj, **config):
msg = config.get('msg', '')
printable = [json.dumps(o, ensure_ascii=False) for o in obj]
print(msg + '\n'.join(printable))
def json_array_equals_ignore_position(self, alist, elist, list_strict=True, dict_strict=True):
"""忽略列表元素位置,比较两个列表是否相等,支持列表元素可以是嵌套的数据 Args: - alist 实际列表 - elist 预期列表 - dict_strict 布尔值,控制字典及其包含的嵌套字典的比较方式, True - 两个字典必须键和值完全一致才相等 False - 只要实际字典的包含有预期字典的键值就认为相等 - list_strict 布尔值,控制列表及其包含的嵌套列表的比较方式, True - 两个列表元素个数必须完全相等,同时元素都一样则认为两个列表相等 False - 只要实际列表包含有预期列表的元素就认为两个列表相等(相当于预期列表的元素是实际列表的元素的子集) """
if list_strict:
if len(alist) != len(elist):
return False
a_nonelist, a_boollist, a_basedata, a_array_list, a_dict_list, a_other_list = self._group(alist)
e_nonelist, e_boollist, e_basedata, e_array_list, e_dict_list, e_other_list = self._group(elist)
noneresult = self._none_equals(a_nonelist, e_nonelist, list_strict)
boolresult = self._bool_equals(a_boollist, e_boollist, list_strict)
bresult = self._basic_data_equals(a_basedata, e_basedata, list_strict)
uresult = self._unknow_type_data_equals(a_other_list, e_other_list, list_strict)
r1 = noneresult and boolresult and bresult and uresult
empty = self.is_all_empty_objs(a_array_list, a_dict_list, e_array_list, e_dict_list)
if (not r1) or empty:
return r1
r2 = self._json_array_equals_ignore_position(a_array_list, e_array_list, list_strict=list_strict, dict_strict=dict_strict)
r3 = self._dictlist_check(a_dict_list, e_dict_list, dict_strict=dict_strict, list_strict=list_strict)
return r1 and r2 and r3
def json_obj_equals(self, adict, edict):
"""判断两个json对象是否完全相等 Args: - adict 实际字典 - edict 预期字典 Useage: self.json_obj_equals({"a":1,"b":2}, {"a":1,"b":2}) >>> True self.json_obj_equals({"a":1,"b":2}, {"a":1}) >>> False self.json_obj_equals({"a":1,"b":{"c":3}}, {"a":1,"b":{"c":3}}) >>> True """
akeys = adict.keys()
ekeys = edict.keys()
if len(akeys) != len(ekeys):
return False
for k in ekeys:
if k not in akeys:
return False
else:
v1 = adict[k]
v2 = edict[k]
if isinstance(v1, (list, tuple)) and isinstance(v2, (list, tuple)):
if not self.json_array_equals(v1, v2):
return False
elif isinstance(v1, dict) and isinstance(v2, dict):
subresult = self.json_obj_equals(v1, v2)
if not subresult:
return False
elif isinstance(v1, bool) or isinstance(v2, bool): # 任意一个是bool值,则进行bool值比较
if not self.all_is_same_bool_value(v1, v2):
return False
elif v1 is None or v2 is None: # 任意一个是None值,则进行None比较
if not self.all_is_none(v1, v2):
return False
else:
if v1 != v2:
return False
return True
def json_array_equals(self, alist, elist):
"""判断json数组是否完全相等,即两个数组的元素个数以及相同位置的元素值必须完全相等,才相等 Args: - alist 实际列表 - elist 预期列表 """
alen = len(alist)
elen = len(elist)
if alen != elen:
return False
for i, v1 in enumerate(elist):
v2 = alist[i]
if isinstance(v1, (list, tuple)) and isinstance(v2, (list, tuple)):
if not self.json_array_equals(v2, v1):
return False
elif isinstance(v1, dict) and isinstance(v2, dict):
if not self.json_obj_equals(v2, v1):
return False
elif isinstance(v1, bool) or isinstance(v2, bool): # 任意一个是bool值,则进行bool值比较
if not self.all_is_same_bool_value(v1, v2):
return False
elif v1 is None or v2 is None: # 任意一个是None值,则进行None比较
if not self.all_is_none(v1, v2):
return False
else:
if v1 != v2:
return False
return True
class Age(object):
def __init__(self, number):
self._number = number
def __eq__(self, other):
return self._number == other._number
if __name__ == "__main__":
checker = JSONCheckpoint()
# ignore_position=False 比较相等(完全一致)
# 即两个值必须完全相等,如果两个值是列表或字典,那么列表及其嵌套列表的元素个数以及相同位置的元素值必须完全相等,
# 字典及其嵌套的子孙字典的键值必须完全一致,才认为则两个值相等
a = [1, 2, {
"age": 18}]
b = [1, 2, {
"age": 18}]
checker.test(a, b, False, ignore_position=False)
a = {
"age": 18, "friends": ["小明", "小红"]}
b = {
"age": 18, "friends": ["小明", "小红"]}
checker.test(a, b, False, ignore_position=False)
# ignore_position=True, list_strict=True, dict_strict=True
# 忽略数组或者嵌套数组中元素的位置,实际和预期数组的元素必须完全相同,实际和预期字典的键值必须完全一致,则认为相等
a = [1, 2, {
"age": 18}]
b = [2, {
"age": 18}, 1]
checker.test(a, b, False, ignore_position=True, list_strict=True, dict_strict=True)
a = {
"age": 18, "friends": ["小红", "小明"]}
b = {
"age": 18, "friends": ["小明", "小红"]}
checker.test(a, b, False, ignore_position=True, list_strict=True, dict_strict=True)
# ignore_position=True, list_strict=False, dict_strict=True
# 忽略数组或者嵌套数组中元素的位置,实际数组完全包含有预期数组的元素,实际和预期字典的键值必须完全一致,则认为相等
a = [1, 2, {
"age": 18}, 3]
b = [2, {
"age": 18}, 1]
checker.test(a, b, False, ignore_position=True, list_strict=False, dict_strict=True)
a = {
"age": 18, "friends": ["小红", "小明", "小霞"]}
b = {
"age": 18, "friends": ["小明", "小红"]}
checker.test(a, b, False, ignore_position=True, list_strict=False, dict_strict=True)
# ignore_position=True, list_strict=True, dict_strict=False
# 忽略数组或者嵌套数组中元素的位置,实际和预期数组的元素必须完全相同,实际字典完全包含有预期字典的键值,则认为相等
a = [1, 2, {
"age": 18, "name": "小玄"}]
b = [2, {
"age": 18}, 1]
checker.test(a, b, False, ignore_position=True, list_strict=True, dict_strict=False)
a = {
"age": 18, "name": "卡罗拉", "friends": ["小红", "小明"]}
b = {
"age": 18, "friends": ["小明", "小红"]}
checker.test(a, b, False, ignore_position=True, list_strict=True, dict_strict=False)
# ignore_position=True, list_strict=False, dict_strict=False
# 忽略数组或者嵌套数组中元素的位置,实际数组完全包含有预期数组的元素,实际字典完全包含有预期字典的键值,则认为相等
a = [1, 2, {
"age": 18, "name": "小玄"}, 3, 2, False, False, None, None, Age(1), Age(1)]
b = [2, {
"age": 18}, 1, 2, False, None, Age(1)]
checker.test(a, b, False, ignore_position=True, list_strict=False, dict_strict=False)
a = {
"age": 18, "name": "卡罗拉", "friends": ["小红", "小明", "小霞"]}
b = {
"age": 18, "friends": ["小明", "小红"]}
checker.test(a, b, False, ignore_position=True, list_strict=False, dict_strict=False)
边栏推荐
- Global and Chinese markets of gps/gnss receiver modules 2022-2028: Research Report on technology, participants, trends, market size and share
- QT waiting box production
- Leetcode top 100 questions 1 Sum of two numbers
- 使用 Nocalhost 开发 Rainbond 上的微服务应用
- Global and Chinese market for kitchen range hoods 2022-2028: Research Report on technology, participants, trends, market size and share
- Mongodb学习篇:安装后的入门第一课
- HDU - 1024 Max Sum Plus Plus(DP)
- Introduction to 3D modeling and processing software Liu Ligang University of science and technology of China
- 数字金额加逗号;js给数字加三位一逗号间隔的两种方法;js数据格式化
- How to meet the requirements of source code confidentiality and source code security management
猜你喜欢

el-form表单新增表单项动态校验;el-form校验动态表单v-if不生效;

Rainbond结合NeuVector实践容器安全管理

如何创建一个根据进度改变颜色的进度条

Fluentd is easy to use. Combined with the rainbow plug-in market, log collection is faster

2/15 (awk, awk conditions, awk processing design can perform additional tasks, and use awk array +for loop to realize advanced search)

Set集合详细讲解
![[data recovery in North Asia] a data recovery case of raid crash caused by hard disk drop during data synchronization of hot spare disk of RAID5 disk array](/img/22/606ff1e8dad3d5896b32d2146b0477.jpg)
[data recovery in North Asia] a data recovery case of raid crash caused by hard disk drop during data synchronization of hot spare disk of RAID5 disk array

Detailed explanation of set

Dynamic verification of new form items in El form; El form verifies that the dynamic form V-IF does not take effect;

Vmware workstation network card settings and three common network modes
随机推荐
QDataStream的简单读写验证
QDataStream的簡單讀寫驗證
Chapitre d'apprentissage mongodb: Introduction à la première leçon après l'installation
Mongodb學習篇:安裝後的入門第一課
Mongodb learning chapter: introduction after installation lesson 1
Fluentd is easy to use. Combined with the rainbow plug-in market, log collection is faster
Application and principle of ThreadPoolExecutor thread pool
Explanation of characteristics of hydraulic slip ring
提高企业产品交付效率系列(1)—— 企业应用一键安装和升级
Detailed explanation of set
Global and Chinese market of paper machine systems 2022-2028: Research Report on technology, participants, trends, market size and share
JDBC common interview questions
Fiber Bragg grating (FBG) notes [1]: waveguide structure and Bragg wavelength derivation
JDBC常见面试题
複制寶貝提示材質不能為空,如何解决?
Series of improving enterprise product delivery efficiency (1) -- one click installation and upgrade of enterprise applications
JS random verification code
工业导电滑环的应用
复制宝贝提示材质不能为空,如何解决?
Leetcode top 100 question 2 Add two numbers