当前位置:网站首页>JSON data comparer
JSON data comparer
2022-07-01 05:35:00 【hotswwkyo】
json Data comparator
Not only support for json object 、 Direct comparison of arrays , It also supports nested complex json Direct comparison of objects and arrays .
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
''' @Author: Si Wenwei '''
import json
class JSONCheckpoint(object):
"""JSON Format data checkpoints , Supports two complex JSON Direct comparison JSON Write the data as the name / It's worth it . name / The value consists of the field name , Followed by a colon and a value :{ "name":"Bill Gates" } stay JSON in , The value must be one of the following data types : character string Numbers object (JSON object ) Array Boolean 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):
""" Compare two objects for equality Args: - actual: actual - expected: expect - ignore_position: Controls whether to call the ignore position comparison function or the exact equality comparison function True - Ignore location False - Completely equal - list_strict: ignore_position by True When , This parameter makes sense - dict_strict: ignore_position by True When , This parameter makes sense """
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):
""" Compare two objects for equality Args: - actual: actual - expected: expect - ignore_position: Controls whether to call the ignore position comparison function or the exact equality comparison function True - Ignore location False - Completely equal - list_strict: ignore_position by True When , This parameter makes sense - dict_strict: ignore_position by True When , This parameter makes sense """
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): # Either one is bool value , Is to bool Value comparison
return self.all_is_same_bool_value(actual, expected)
elif expected is None or actual is None: # Either one is None value , Is to None Compare
return self.all_is_none(actual, expected)
else:
return actual == expected
def _group(self, dlist):
""" Group child elements of a list by data type , The grouping rules are as follows : - None Divided into one group - Boolean value Divided into one group - character string integer floating-point Divided into one group - list Yuan Zu Group together - Dictionary types are grouped - In addition to the above, other types are divided into a group """
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 Object type data is equivalent to python Dictionary , Compare two dictionaries for equality , Support nested dictionaries and list primitives Args: - adict Actual Dictionary - edict Expected dictionary - dict_strict Boolean value , Controls how dictionaries and the nested dictionaries they contain are compared , True - Two dictionaries must have exactly the same key and value to be equal False - As long as the actual dictionary contains the expected dictionary key values, they are considered equal - list_strict Boolean value , Controls how lists and nested lists they contain are compared , True - The number of two list elements must be exactly the same , At the same time, if the elements are the same, the two lists are equal False - As long as the actual list contains elements of the expected list, the two lists are considered equal ( The elements equivalent to the expected list are subsets of the elements of the actual list ) 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): # Either one is bool value , Is to bool Value comparison
if not self.all_is_same_bool_value(v1, v2):
return False
elif v1 is None or v2 is None: # Either one is None value , Is to None Compare
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 In the actual list, all the sub elements of the list make up the list - expected The expected list consists of all the child elements of the list - list_strict Boolean value , Controls how lists and nested lists they contain are compared , True - The number of two list elements must be exactly the same , At the same time, if the elements are the same, the two lists are equal False - As long as the actual list contains elements of the expected list, the two lists are considered equal ( The elements equivalent to the expected list are subsets of the elements of the actual list ) - dict_strict Boolean value , Controls how dictionaries and the nested dictionaries they contain are compared , True - Two dictionaries must have exactly the same key and value to be equal False - As long as the actual dictionary contains the expected dictionary key values, they are considered equal """
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 In the actual list, all the sub elements of the dictionary make up the list - expected The expected list consists of all the sub elements of the dictionary - dict_strict Boolean value , Controls how dictionaries and the nested dictionaries they contain are compared , True - Two dictionaries must have exactly the same key and value to be equal False - As long as the actual dictionary contains the expected dictionary key values, they are considered equal - list_strict Boolean value , Controls how lists and nested lists they contain are compared , True - The number of two list elements must be exactly the same , At the same time, if the elements are the same, the two lists are equal False - As long as the actual list contains elements of the expected list, the two lists are considered equal ( The elements equivalent to the expected list are subsets of the elements of the actual list ) """
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):
""" Ignore list element position , Compare two lists for equality , Support that list elements can be nested data Args: - alist Actual list - elist Expected list - dict_strict Boolean value , Controls how dictionaries and the nested dictionaries they contain are compared , True - Two dictionaries must have exactly the same key and value to be equal False - As long as the actual dictionary contains the expected dictionary key values, they are considered equal - list_strict Boolean value , Controls how lists and nested lists they contain are compared , True - The number of two list elements must be exactly the same , At the same time, if the elements are the same, the two lists are equal False - As long as the actual list contains elements of the expected list, the two lists are considered equal ( The elements equivalent to the expected list are subsets of the elements of the actual list ) """
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):
""" Whether two json Whether the objects are exactly equal Args: - adict Actual Dictionary - edict Expected dictionary 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): # Either one is bool value , Is to bool Value comparison
if not self.all_is_same_bool_value(v1, v2):
return False
elif v1 is None or v2 is None: # Either one is None value , Is to None Compare
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):
""" Judge json Whether the arrays are exactly equal , That is, the number of elements of the two arrays and the element values at the same position must be exactly the same , It's the same Args: - alist Actual list - elist Expected list """
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): # Either one is bool value , Is to bool Value comparison
if not self.all_is_same_bool_value(v1, v2):
return False
elif v1 is None or v2 is None: # Either one is None value , Is to None Compare
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 More equal ( Exactly the same )
# That is, the two values must be exactly equal , If the two values are lists or dictionaries , Then the number of elements in the list and its nested list and the element value at the same position must be exactly the same ,
# The key values of the dictionary and its nested descendant dictionaries must be exactly the same , Then the two values are equal
a = [1, 2, {
"age": 18}]
b = [1, 2, {
"age": 18}]
checker.test(a, b, False, ignore_position=False)
a = {
"age": 18, "friends": [" Xiao Ming ", " Xiaohong "]}
b = {
"age": 18, "friends": [" Xiao Ming ", " Xiaohong "]}
checker.test(a, b, False, ignore_position=False)
# ignore_position=True, list_strict=True, dict_strict=True
# Ignore the position of elements in an array or nested array , The elements of the actual and expected arrays must be exactly the same , The actual and expected dictionary keys must be exactly the same , Is considered equal
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": [" Xiaohong ", " Xiao Ming "]}
b = {
"age": 18, "friends": [" Xiao Ming ", " Xiaohong "]}
checker.test(a, b, False, ignore_position=True, list_strict=True, dict_strict=True)
# ignore_position=True, list_strict=False, dict_strict=True
# Ignore the position of elements in an array or nested array , The actual array contains exactly the elements of the expected array , The actual and expected dictionary keys must be exactly the same , Is considered equal
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": [" Xiaohong ", " Xiao Ming ", " Kasumi "]}
b = {
"age": 18, "friends": [" Xiao Ming ", " Xiaohong "]}
checker.test(a, b, False, ignore_position=True, list_strict=False, dict_strict=True)
# ignore_position=True, list_strict=True, dict_strict=False
# Ignore the position of elements in an array or nested array , The elements of the actual and expected arrays must be exactly the same , The actual dictionary contains exactly the key values of the expected dictionary , Is considered equal
a = [1, 2, {
"age": 18, "name": " Xiao Xuan "}]
b = [2, {
"age": 18}, 1]
checker.test(a, b, False, ignore_position=True, list_strict=True, dict_strict=False)
a = {
"age": 18, "name": " corolla ", "friends": [" Xiaohong ", " Xiao Ming "]}
b = {
"age": 18, "friends": [" Xiao Ming ", " Xiaohong "]}
checker.test(a, b, False, ignore_position=True, list_strict=True, dict_strict=False)
# ignore_position=True, list_strict=False, dict_strict=False
# Ignore the position of elements in an array or nested array , The actual array contains exactly the elements of the expected array , The actual dictionary contains exactly the key values of the expected dictionary , Is considered equal
a = [1, 2, {
"age": 18, "name": " Xiao Xuan "}, 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": " corolla ", "friends": [" Xiaohong ", " Xiao Ming ", " Kasumi "]}
b = {
"age": 18, "friends": [" Xiao Ming ", " Xiaohong "]}
checker.test(a, b, False, ignore_position=True, list_strict=False, dict_strict=False)
边栏推荐
- 导电滑环短路的原因以及应对措施
- Leetcode top 100 question 2 Add two numbers
- Things generated by busybox
- 0xc000007b the application cannot start the solution normally (the pro test is valid)
- Introduction to 3D modeling and processing software Liu Ligang University of science and technology of China
- Simple implementation of database connection pool
- 工业导电滑环的应用
- Software intelligence: the "world" and "boundary" of AI sentient beings in AAAs system
- Mongodb learning chapter: introduction after installation lesson 1
- 如何开始学剪辑?零基础详细解析
猜你喜欢

C# wpf 使用DockPanel实现截屏框

Tar command

激活函数简述

教务管理系统(免费源码获取)

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

CockroachDB 分布式事务源码分析之 TxnCoordSender

Use and principle of wait notify

Use and principle of AQS related implementation classes

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

Actual combat: basic use of Redux
随机推荐
多表操作-外键级联操作
液压滑环的特点讲解
Things generated by busybox
Actual combat: basic use of Redux
RecycleView的一些使用
Flowable source code comment (XXXIX) task listener
Typeorm framework
Mathematical knowledge: finding the number of divisors
JS random verification code
Programmers dig "holes" to get rich: if they find a loophole, they will be rewarded 12.72 million yuan
[RootersCTF2019]babyWeb
Redis数据库的部署及常用命令
轻松上手Fluentd,结合 Rainbond 插件市场,日志收集更快捷
Mongodb learning chapter: introduction after installation lesson 1
导电滑环短路的原因以及应对措施
Day 05 - file operation function
Flutter can refresh data every time the interface comes in
Use and principle of AQS related implementation classes
In depth understanding of condition source code interpretation and analysis of concurrent programming
Spanner 论文小结