【json/regex】将嵌套对象生成的json文进行内部整形排序后再输出
下载地址:https://files.cnblogs.com/files/xiandedanteng/jsonformat20191126-2.zip
注意:本文仅为draft1版本,还有待完善。
先看整形效果(同级别按字典序排列,层次缩进,化单行为多行):
原句:{"depts":[{"emps":[{"age":23,"id":1,"male":true,"name":"Andy","phone":"13000000001"},{"age":31,"id":2,"male":false,"name":"Bill","phone":"14000000001"},{"age":37,"id":3,"male":true,"name":"Cindy","phone":"15000000001"},{"age":41,"id":4,"male":false,"name":"Douglas","phone":"16000000001"},{"age":43,"id":5,"male":true,"name":"Eliot","phone":"17000000001"}],"id":"001","name":"Sales"},{"emps":[{"age":47,"id":6,"male":true,"name":"Felix","phone":"18000000001"},{"age":53,"id":7,"male":false,"name":"Gates","phone":"19000000001"},{"age":59,"id":8,"male":true,"name":"Hilton","phone":"2000000001"}],"id":"002","name":"Develop"}],"id":"01","name":"doogle"}
整形后的的文本:{
"depts":[ {
"emps":[ {
"age":23,
"id":1,
"male":true,
"name":"Andy",
"phone":"13000000001",
},
{
"age":31,
"id":2,
"male":false,
"name":"Bill",
"phone":"14000000001",
},
{
"age":37,
"id":3,
"male":true,
"name":"Cindy",
"phone":"15000000001",
},
{
"age":41,
"id":4,
"male":false,
"name":"Douglas",
"phone":"16000000001",
},
{
"age":43,
"id":5,
"male":true,
"name":"Eliot",
"phone":"17000000001",
},
],
"id":"001",
"name":"Sales",
},
{
"emps":[ {
"age":47,
"id":6,
"male":true,
"name":"Felix",
"phone":"18000000001",
},
{
"age":53,
"id":7,
"male":false,
"name":"Gates",
"phone":"19000000001",
},
{
"age":59,
"id":8,
"male":true,
"name":"Hilton",
"phone":"2000000001",
},
],
"id":"002",
"name":"Develop",
},
],
"id":"01",
"name":"doogle",
}
这个效果是下面这个类做出来的,主要利用了栈,哈希表和正则表达式:
package com.hy;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sf.json.JSONObject;
class StrDepth{
String str;
int depth;
public StrDepth(String str,int depth) {
this.str=str;
this.depth=depth;
}
}
/**
* 嵌套Json排序整形类
* @author 逆火
*
* 2019年11月24日 下午3:37:40
*/
public class NestedJsonSorter {
// 每个栈替换对象的序列号
private int serialNumber=0;
// 存放栈替换对象的哈希表
private Map<String,StrDepth> map;
// 整形排序结束的最终结果
private String result;
/**
* 构造函数
* @param jsonStr
*/
public NestedJsonSorter(String jsonStr) {
Stack<String> stk=new Stack<String>();
map=new LinkedHashMap<String,StrDepth>();
// 利用栈进行嵌套处理
String line="";
for(int i=0;i<jsonStr.length();i++){
char c=jsonStr.charAt(i);
if(c=='['){
stk.push(line);
line="";
}else if(c==']') {
int depth=stk.size();
String sid=storeInMap(line,depth);
line=stk.pop()+"["+sid+repeatedSpace(depth)+"]";
}else{
line+=c;
}
}
// 最后留下ROOT
SimpleJsonSorter sjs=new SimpleJsonSorter(line,0);
String rawString=sjs.getFormattedJson();
// 用正则表达式对SN0001,SN0002还原成其代表的字符串
java.util.regex.Pattern pattern=Pattern.compile("SN\\d{4}");
Matcher matcher=pattern.matcher(rawString);
while(matcher.find()) {
String key=matcher.group(0);
rawString=rawString.replace(key, fetchValue(key));
matcher=pattern.matcher(rawString);
}
result=rawString;
}
// 得到整形排序结束的最终结果
public String getFormattedResult() {
return result;
}
/**
* 得到重复多次数的四个空格,放在行头当竖向定位用
* @param n
* @return
*/
private static String repeatedSpace(int n) {
return String.join("", Collections.nCopies(n, " "));
}
/**
* 从哈希表里取得SN000X代表的值
* @param key
* @return
*/
private String fetchValue(String key) {
StrDepth value=map.get(key);
map.remove(key);
return value.str;
}
/**
* 把中括号内内容存入map
* @param str
* @param depth
* @return
*/
private String storeInMap(String str,int depth) {
serialNumber++;
String key="SN"+String.format("%04d", serialNumber);
StringBuilder sb=new StringBuilder();
String[] arr=str.split("(?<=[}])\\s*,\\s*(?=[{])"); // 注意要增加逗号两边的空白字符 2019-11-26
for(String objStr:arr) {
SimpleJsonSorter sjs=new SimpleJsonSorter(objStr,depth);
String retval=sjs.getFormattedJson();
sb.append(retval+",\n");
}
String objsStr=sb.toString();
StrDepth value=new StrDepth(objsStr,depth);
map.put(key, value);
return key;
}
public static void main(String[] args) {
Dept salesDept=new Dept();
salesDept.setId("001");
salesDept.setName("Sales");
salesDept.addEmp(new Emp(1,23,"Andy",true,"13000000001"));
salesDept.addEmp(new Emp(2,31,"Bill",false,"14000000001"));
salesDept.addEmp(new Emp(3,37,"Cindy",true,"15000000001"));
salesDept.addEmp(new Emp(4,41,"Douglas",false,"16000000001"));
salesDept.addEmp(new Emp(5,43,"Eliot",true,"17000000001"));
Dept devDept=new Dept();
devDept.setId("002");
devDept.setName("Develop");
devDept.addEmp(new Emp(6,47,"Felix",true,"18000000001"));
devDept.addEmp(new Emp(7,53,"Gates",false,"19000000001"));
devDept.addEmp(new Emp(8,59,"Hilton",true,"2000000001"));
Company company=new Company();
company.setId("01");
company.setName("doogle");
company.addDept(salesDept);
company.addDept(devDept);
JSONObject jobj = JSONObject.fromObject(company);
System.out.println(jobj);
NestedJsonSorter njs=new NestedJsonSorter(jobj.toString());
System.out.println(njs.getFormattedResult());
}
}
对于非嵌套的Json,则用上一篇里提到的SimpleJsonSorter类就行了:
package com.hy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sf.json.JSONObject;
/**
* 简单Json排序整形类
* @author 逆火
*
* 2019年11月24日 上午11:57:39
*/
public class SimpleJsonSorter {
private int depth;
private List<KeyValue> kvList;
public SimpleJsonSorter(String jsonStr,int depth){
this.depth=depth;
kvList=new ArrayList<KeyValue>();
java.util.regex.Pattern pattern=Pattern.compile("(\"([_a-zA-Z]+[_a-zA-Z0-9]*)\")\\s*[:]\\s*([^,}]+)");
Matcher matcher=pattern.matcher(jsonStr);
while(matcher.find()) {
//System.out.println( matcher.group(1)+ ":"+matcher.group(3));
kvList.add(new KeyValue(matcher.group(1),matcher.group(3)));
}
}
public String getFormattedJson() {
Collections.sort(kvList);
String prefix=getRepeatSpace(this.depth);
StringBuilder sb=new StringBuilder();
sb.append(prefix+"{\n");
for(KeyValue kv:kvList) {
sb.append(prefix+kv.key+":"+kv.value+",\n");
}
sb.append(prefix+"}");
return sb.toString();
}
private String getRepeatSpace(int n) {
return String.join("", Collections.nCopies(n, " "));
}
protected final class KeyValue implements Comparable<KeyValue>{
private String key;
private String value;
public KeyValue(String key,String value) {
this.key=key;
this.value=value;
}
public int compareTo(KeyValue other) {
return this.key.compareTo(other.key);
}
}
public static void main(String[] args) {
Emp felix=new Emp(6,47,"费力克死",false,"18000000001");
JSONObject deptJson = JSONObject.fromObject(felix);
String jsonString=deptJson.toString();
System.out.println(jsonString);
SimpleJsonSorter sjs=new SimpleJsonSorter(jsonString,2);
System.out.println(sjs.getFormattedJson());
}
}
至于Company,Dept,Emp等类,则是普通的Bean,没啥花头:
公司类:
package com.hy;
import java.util.ArrayList;
import java.util.List;
public class Company {
private String id;
private String name;
private List<Dept> depts;
public Company addDept(Dept dept) {
if(depts==null) {
depts=new ArrayList<Dept>();
}
depts.add(dept);
return this;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Dept> getDepts() {
return depts;
}
public void setDepts(List<Dept> depts) {
this.depts = depts;
}
}
部门类:
package com.hy;
import java.util.ArrayList;
import java.util.List;
public class Dept {
private String id;
private String name;
private List<Emp> emps;
public Dept addEmp(Emp emp) {
if(emps==null) {
emps=new ArrayList<Emp>();
}
emps.add(emp);
return this;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Emp> getEmps() {
return emps;
}
public void setEmps(List<Emp> emps) {
this.emps = emps;
}
}
雇员类:
package com.hy;
public class Emp {
private int id;
private int age;
private String name;
private boolean isMale;
private String phone;
public Emp() {
}
public Emp(int id,int age,String name,boolean isMale,String phone) {
this.id=id;
this.age=age;
this.name=name;
this.isMale=isMale;
this.phone=phone;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isMale() {
return isMale;
}
public void setMale(boolean isMale) {
this.isMale = isMale;
}
}
对于嵌套对象解析,并非一定要用编译方式,还是有别的路可以走的。
--END-- 2019年11月24日19:50:49
【json/regex】将嵌套对象生成的json文进行内部整形排序后再输出的更多相关文章
- 【json/regex】将简单对象生成的json文进行内部排序后再输出
有这样一个实体类: package com.hy; public class Emp { private int id; private int age; private String name; p ...
- 做一次面向对象的体操:将JSON字符串转换为嵌套对象的一种方法
背景与问题 在 <一个略复杂的数据映射聚合例子及代码重构> 一文中,将一个JSON字符串转成了所需要的订单信息Map.尽管做了代码重构和配置化,过程式的代码仍然显得晦涩难懂,并且客户端使用 ...
- ObjC 利用反射和KVC实现嵌套对象序列化成JSON数据
原理: 0.创建一个新的可变字典:NSMutableDictionary 1.采用class_copyPropertyList函数遍历对象的属性 2.property_getName获取属性名,val ...
- C# json提取多层嵌套到数组-- C# json 数组
json比一般格式再复杂点的就像数组一样,有多层嵌套,研究了一下,记录代码如下: string jsonText = "{'name':'test','phone':'18888888888 ...
- java对象转化为json字符串并传到前台
package cc.util; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import ...
- Json对象与Json字符串的转化、JSON字符串与Java对象的转换
一.Json对象与Json字符串的转化 1.jQuery插件支持的转换方式: $.parseJSON( jsonstr ); //jQuery.parseJSON(jsonstr),可以将json字符 ...
- 【Python】将对象存成json文件及从json取出对象
常用代码,单拎出来以备查. 对象存json文件: import json obj={'name':'张有财','age':39,'arr':[2,34,5,6,7,88,'李有钱']} with op ...
- Json对象与Json字符串的转化、JSON字符串与Java对象的转换(转)
一.Json对象与Json字符串的转化 1.jQuery插件支持的转换方式: $.parseJSON( jsonstr ); //jQuery.parseJSON(jsonstr),可以将json字符 ...
- JSON字符串和Javascript对象字面量
JSON字符串和Javascript对象字面量 JSON是基于Javascript语法的一个子集而创建的,特别是对象和数组字面量语法. 正是由于JSON的这种特殊来历,导致很多Javascript程序 ...
随机推荐
- 安装CDH 5.15.1详解
安装CDH 5.15.1详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.安装Cloudera Manager 和CDH 1>.登陆Cloudera Manager ...
- InteiiJ IDEA中如何制定制定哪一个配置文件
项目下有好些application.property文件 彼此之间也不是什么 从application.property中指定dev就去对应dev的关系 就想用我本地的数据库 于是添加了一个appl ...
- 使用SikuliX定位Object(flash)元素
先说一下背景,这个是我们测试的系统上的一个上传文件的地方,但是用传统的selenium方法很难定位的到.具体的样子是下面这样的. 使用id等属性定位做点击操作好像不能直接操作.无奈之下,只好从网上找找 ...
- 关于C3P0-mySQL关于url的细节问题
1.为url设置?useUnicode=true&characterEncoding=UTF-8 为了统一编码,我们会为数据库封装的实体类加上上面的那句话,但是C3P0数据库连接池是xml配置 ...
- K8s中的多容器Pod和Pod内容器间通信
容器(Container)常被用来解决比如微服务的单个问题,但在实际场景中,问题的解决往往需要多容器方案.本文会讨论将多个容器整合进单个Kubernetes Pod 中,以及Pod中的容器之间是如何通 ...
- zentaopms - 禅道项目管理系统部署
概述 禅道是开源免费的项目管理软件 使用步骤 管理员 添加组织 添加用户 用户权限管理(通过分组确定权限) 产品经理 添加产品 添加模块(隶属于产品) 添加需求(隶属于模块) 添加计划(计划形成“路线 ...
- 4.1 vue-resource
全局拦截器.配置全局地址等:
- c#嵌套CMD窗口
解决方法一: 自己放一个文本框,改成黑色,然后输入命令,执行时,你Process.Start cmd ,此时CMD窗口不显示,然后,将CMD的返回值,再取出来,设回文本框. 如何用这种方法实时获取cm ...
- Spring Jpa
一对多 1.application.properties 2.Dao层 3.Controller 3.1级联添加数据 3.2查询数据 3.3删除数据 多对多 1.查询 2.添加
- C++数组排序泛型算法
//数组排序泛型算法 #include <vector> #include <iostream> #include <algorithm> //内置泛型算法头文件 ...