废话少说,直接入题。
在面向对象语言中,经常会比较两个对象是否相等,而比较的大多是实体类实例,也就是封装数据的那些类实例,或者是Map、List互相嵌套成的复杂数据结构。
比较对象是否相等,常见的思路是重写equals方法,但鉴于对象的种类多变,嵌套层次复杂,仅仅靠重写equals是很难实现的。
小菜的思路是可以把对象序列化,由于这些对象均是用来表达数据结构,因此可以直接转换成JSON字符串,用字符串来描述数据结构,避免实现Serializable接口。将对象序列化成字符串后,比较是否相等就相对简单了。
小菜提供的正是比较两个JSON串是否相等的方法,并不是说JSON串完全一样才叫相等,对于List(或数组)结构而言,如果仅仅是元素排列顺序不同,也是相等的。
为了保证方法的准确性,请传入标准的JSON串,也就是说key也要加双引号。用过js的童鞋可能会被误导:我在js中写的JSON,key可以不加双引号啊!实际上,你在js中写的是js语言的Object,并不是JSON,只不过它的语法和JSON非常像而已,JSON仅仅是一种字符串规范,而且真正的JSON只有一种,那就是key加了双引号的!
另外,此方法不依赖任何第三方包。
最后声明,由于数据结构复杂,小菜对这个方法不可能进行遍历性测试,所以这个方法的准确性有待考究,请谨慎使用!如有问题,欢迎反馈!
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 比较两个json串是否相同
* @param j1 第一个json串(json串中不能有换行)
* @param j2 第二个json串(json串中不能有换行)
* @return 布尔型比较结果
*/
public static boolean jsonEquals(String j1,String j2){
//将json中表示list的[]替换成{}。思想:只保留层次结构,不区分类型
//这样直接替换,可能会导致某些value中的符号也被替换,但是不影响结果,因为j1、j2的变化是相对的
j1 = j1.replaceAll("\\[", "{");
j1 = j1.replaceAll("]", "}");
j2 = j2.replaceAll("\\[", "{");
j2 = j2.replaceAll("]", "}");
//将json中,字符串型的value中的{},字符替换掉,防止干扰(并没有去除key中的,因为不可能存在那样的变量名)
//未转义regex:(?<=:")(([^"]*\{[^"]*)|([^"]*\}[^"]*)|([^"]*,[^"]*))(?=")
Pattern pattern = Pattern.compile("(?<=:\")(([^\"]*\\{[^\"]*)|([^\"]*\\}[^\"]*)|([^\"]*,[^\"]*))(?=\")");
j1 = cleanStr4Special(j1, pattern.matcher(j1));
j2 = cleanStr4Special(j2, pattern.matcher(j2));
//转义字符串value中的空格
//未转义regex:"[^",]*?\s+?[^",]*?"
pattern = Pattern.compile("\"[^\",]*?\\s+?[^\",]*?\"");
j1 = cleanStr4Space(j1, pattern.matcher(j1));
j2 = cleanStr4Space(j2, pattern.matcher(j2));
//现在可以安全的全局性去掉空格
j1 = j1.replaceAll(" ", "");
j2 = j2.replaceAll(" ", "");
//调用递归方法
return compareAtom(j1,j2);
}
/**
* 比较字符串核心递归方法
* @param j1
* @param j2
* @return
*/
private static boolean compareAtom(String j1,String j2){
if(!j1.equals("?:\"?\"")){
//取出最深层原子
String a1 = j1.split("\\{",-1)[j1.split("\\{",-1).length-1].split("}",-1)[0];
String a2 = j2.split("\\{",-1)[j2.split("\\{",-1).length-1].split("}",-1)[0];
String j2_ = j2;
String a2_ = a2;
//转换成原子项
String i1[] = a1.split(",");
//在同级原子中寻找相同的原子
while(!a2.startsWith(",") &&
!a2.endsWith(",") &&
a2.indexOf(":,")<0 &&
a2.indexOf(",,")<0
){
//遍历消除
for(String s : i1){
a2_ = a2_.replace(s,"");
}
//此时a2_剩下的全是逗号,如果长度正好等于i1的长度-1,说明相等
if(a2_.length() == i1.length-1){
//相等则从j1、j2中消除,消除不能简单的替换,因为其他位置可能有相同的结构,必须从当前位置上消除
int index = 0;
index = j1.lastIndexOf("{" + a1 + "}");
j1 = j1.substring(0, index)+j1.substring(index).replace("{" + a1 + "}", "?:\"?\"");
index = j2.lastIndexOf("{" + a2 + "}");
j2 = j2.substring(0, index)+j2.substring(index).replace("{" + a2 + "}", "?:\"?\"");
//递归
return compareAtom(j1, j2);
}else{
//寻找下一个同级原子
j2_ = j2_.replace("{" + a2 + "}", "");
a2 = j2_.split("\\{",-1)[j2_.split("\\{",-1).length-1].split("}",-1)[0];
a2_ = a2;
}
}
return false;
}else{
//比较是否相同
return j1.equals(j2);
}
}
/**
* json字符串特殊字符清理辅助方法
* @param j 需要清理的json字符串
* @param matcher 正则表达式匹配对象
* @return 净化的json串
*/
private static String cleanStr4Special(String j,Matcher matcher){
String group = "";
String groupNew = "";
while(matcher.find()){
group = matcher.group();
groupNew = group.replaceAll("\\{", "A");
groupNew = groupNew.replaceAll("}", "B");
groupNew = groupNew.replaceAll(",", "C");
j = j.replace(group, groupNew);
}
return j;
}
/**
* json串字符串类型的value中的空格清理辅助方法
* @param j 需要清理的json字符串
* @param matcher 正则表达式匹配对象
* @return 净化的json串
*/
private static String cleanStr4Space(String j,Matcher matcher){
String group = "";
String groupNew = "";
while(matcher.find()){
group = matcher.group();
groupNew = group.replaceAll(" ", "S");
j = j.replace(group, groupNew);
}
return j;
}
9-2、大型项目的接口自动化实践记录----递归判断两个json串是否相等
1.已知json串构成的情况下判断 先构造一下场景,假设已经把各个数据都移除掉不对比的字段 图1 预期.实际结果,复杂接口返回多层嵌套json时,同下 图2 预期.实际结果值为:{child_json ...
类对象序列化为json串,json串反序列化为类对象
1.类对象序列化为json串: 方法一: class P(object): def __init__(self,name,age,sex): self.name=name self.age=age s ...
python实现比对两个json串的方法
记录瞬间 前段时间为了解决一些实际问题,引出了要对json字符串进行比对的需求. 觉得有意义,作以简单记录. # 比对数据 def compare_data(set_key, src_data, ds ...
[原创] C# dynamic拼接Json串
using Newtonsoft.Json; 之前拼接两个json串,是用的这样的代码 , json1.Length - ); json2 = json2.Insert(json2 - , tmp); ...
Java开发笔记(一百零八)JSON串的定义和解析
前面提到URL尾巴支持添加请求参数,具体格式形如“参数A名称=A参数值&参数B名称=B参数值”,可是这种格式只能传递简单的键值对信息,不能传递结构化数据,也无法传递数组形式的参数,因而它不适用 ...
用Newtonsoft将json串转为对象的方法(详解)
首先,将json串转为一个JObject对象: JObject jo = (JObject)JsonConvert.DeserializeObject(CurrentSelectedItemReq) ...
[MVC_Json序列化]Json字符串反序列化成C#对象
上一篇中有Json序列化相关问题得到了解决. 那么结果集为Json串时,如何将Json串转成C#对象呢? 现举例说明: -现有如下字符串数据 string k = "{\"ring ...
spring入门(七)【springMVC返回json串】
现在多数的应用为了提高交互性多使用异步刷新,即在不刷新整个页面的情况下,只刷新局部,局部刷新用得最多就是ajax,ajax和后台进行交互的数据格式使用的最多的是JSON,这里简单描述,在springm ...
关于遍历javascript 中的json串浏览器输出的结果不统一的情况
我们在做项目的时候经常会用到javascript的json. 首先说一下javascript的json串是什么,json串属于javascript的一个对象,有键和值对应的对象. 一般的格式是: a ...
随机推荐
CodeForces 743B Chloe and the sequence (递归)
题意:给定n和k,求第n个序列中第k个数是多少,序列是这样构造,原来只有1,然后再copy一遍放在到后面再在中间放上一个没有出现过的最小整数,就变成了 121,下次就成了1213121. 析:很明显是 ...
Codeforces Round #360 (Div. 1) D. Dividing Kingdom II 并查集求奇偶元环
D. Dividing Kingdom II Long time ago, there was a great kingdom and it was being ruled by The Grea ...
jsp分页
UEP-标签
这里的标签都是常用不好理解的: formatfunc="showFormatNumer" 显示数字在页面上 ockedcolumnnum="6" 几列是不动的 ...
9. Fizz Buzz 问题
Description Given number n. Print number from 1 to n. But: when number is divided by 3, print " ...
C# 判断一个文本文件的编码格式(转载)
文件的字符集在Windows下有两种,一种是ANSI,一种Unicode.对于Unicode,Windows支持了它的三种编码方式,一种是小尾编码(Unicode),一种是大尾编码(BigEndian ...
把一个List<;T>;的数据复制至另一个List<;T>;
把一个数据集List复制至到另一个数据集List. 方法一,可以使用循环,然后把每一个T添加至另一个集合中去: public void ListDemo() { , ...
Mybatis标签bind用法
Mybatis使用bind元素进行模糊查询,不用在乎数据库是mysql还是oracle从而提高可移植性 使用bind元素传递多个参数 public List findSt ...
bash 定时任务
time1=$(date +%s -d '2014-01-13 22:46:05') for((;;)) do time2=$(date +%s) time3=$((time1 - time2)) ] ...
ReentrantLock与synchronized
1.ReentrantLock 拥有Synchronized相同的并发性和内存语义,此外还多了 锁投票,定时锁等候和中断锁等候 线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O ...