Python:如何比较字段长度可变的两个JSON(求替代方案)
关于JSON差异对比的优化疑问
我现在实现了一段基于字符串拆分的diff代码用来对比JSON,思路是把JSON字符串拆分成片段后借助difflib生成差异结果。但遇到字段(键和值)长度可变的JSON时(比如下面的示例),总觉得这种字符串层面的对比不够精准,想问问有没有更合适的比较方法?
我的现有代码
def diffjson(found, expected): '''diff two json strings''' found = found.split() expected = expected.split() return difflist(found, expected, fromfile="found", tofile="expected", rstrip=True) def difflist(fromlines, tolines, fromfile=None, tofile=None, quiet=False, addnl=None, rstrip=False): if rstrip: fromlines = [x.rstrip() for x in fromlines if x != ''] tolines = [x.rstrip() for x in tolines if x != ''] diff = difflib.unified_diff(fromlines, tolines, fromfile, tofile, n=5) diff = list(diff) if len(diff): if not quiet: if addnl: ret = '' for x in diff: ret = ret + (x) ret = ret + (addnl) else: ret = diff return ret else: return True
示例待比较JSON
JSON1
{"1iG5NDGVre": {"118": ["test1", "test2", "test3", "tcp", "22", "Red", "0.0.0.0/0"]}}
JSON2
{"1iG5NDGVre": {"118": ["test1", "test2", "test3", "tcp", "22", "Red", "Blue", "0.0.0.0/0"]}}
推荐的优化方案
直接对JSON字符串做拆分对比的问题在于,它只是在文本层面找差异,完全忽略了JSON本身的结构化特性——比如你的示例里,只是数组多了一个元素,但字符串拆分后可能会把整个数组行当成差异,没法精准定位到是哪个元素新增了。更靠谱的做法是先把JSON解析成Python的字典/列表结构,再进行结构化差异对比。
这里给你几个具体的思路:
1. 手动递归遍历结构化数据
自己写递归函数,遍历两个解析后的JSON结构(字典或列表),逐一对比每个层级的键、值、数组元素:
- 对于字典:对比键的集合,找出新增/缺失的键,再递归对比对应的值
- 对于列表:可以用类似最长公共子序列的方法找新增/删除的元素,或者如果元素是有序的,逐个索引对比
- 最后把差异整理成清晰的格式(比如标记出哪个路径下的元素新增/修改/删除)
2. 利用成熟的第三方库
不用重复造轮子,很多库已经实现了结构化JSON对比:
deepdiff:这是最常用的之一,能精准找出嵌套结构里的新增、删除、修改项,还支持忽略某些字段、排序数组等功能。示例用法:from deepdiff import DeepDiff json1 = {"1iG5NDGVre": {"118": ["test1", "test2", "test3", "tcp", "22", "Red", "0.0.0.0/0"]}} json2 = {"1iG5NDGVre": {"118": ["test1", "test2", "test3", "tcp", "22", "Red", "Blue", "0.0.0.0/0"]}} diff = DeepDiff(json1, json2) print(diff) # 输出会清晰显示数组里新增了元素"Blue",以及对应的路径jsondiff:专注于JSON的差异对比,支持生成JSON Patch格式的差异结果,适合需要后续应用差异的场景。difflib结合结构化输出:如果不想用第三方库,可以先把解析后的JSON用json.dumps格式化输出(比如加上indent=2、sort_keys=True),再用difflib对比格式化后的字符串——这样文本差异会更贴近结构化差异,比如数组新增元素会单独占一行,更容易定位。
3. 针对你的场景的小改进
如果暂时不想换库,至少先把JSON解析后重新格式化再做字符串对比,比如:
import json def diffjson(found, expected): # 先解析成结构化数据,再格式化输出成统一格式的字符串 def format_json(s): return json.dumps(json.loads(s), indent=2, sort_keys=True) found_formatted = format_json(found).splitlines() expected_formatted = format_json(expected).splitlines() return difflist(found_formatted, expected_formatted, fromfile="found", tofile="expected", rstrip=True)
这样处理后,你的示例里新增的"Blue"会单独在一行,difflib就能精准显示这一行的差异,而不是把整个数组行当成差异。
内容的提问来源于stack exchange,提问作者dev
相关产品推荐
相关产品推荐

