【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程序 ...
随机推荐
- TFTP启动内核、设备树,NFS启动FS
一.软硬件平台 1.开发板:创龙AM3359核心板,网口采用RMII形式. 2.UBOOT版本:U-Boot-2016.05,采用FDT和DM. 3.交换芯片MARVELL的88E6321. 二.问题 ...
- visual studio 应用场景
- QEMU简介
参考:What Is the Difference between QEMU and KVM? 注意:上面参考文章有个错误,他把KVM算成类型一虚拟化,应该是类型2虚拟化. 关于类型一虚拟化和类型二虚 ...
- 迷你商城后台管理系统————stage1需求分析
PS:迷你商城后台管理系统---需求分析.docx下载~click me 迷你商城后台管理系统-- 需求分析 1. 引言 作为互联网热潮的崛起,消费者们的普遍差异化,实体商城要想在互联网的浪潮中继续发 ...
- SpringCloud学习心得—1.2—Eureka注册中心的密码认证、高可用的设置
SpringCloud学习心得—1.2—Eureka注册中心的密码认证.高可用的设置 这是相关代码 链接 Eureka开启密码配置 添加依赖 <dependency> <grou ...
- go cache
go 编译, 或是安装库的时候,产生的日志量很大 go env 删除掉这个log.txt文件,系统空间瞬间就够了
- awk命令笔记
awk是啥? awk(奥克)是linux中一个强大的分析工具,linux面试必考 [root@rainbol ~]# awk Usage: awk [POSIX or GNU style option ...
- 《The One!团队》第八次作业:ALPHA冲刺(二)
项目 内容 作业所属课程 所属课程 作业要求 作业要求 团队名称 < The One !> 作业学习目标 (1)掌握软件测试基础技术.(2)学习迭代式增量软件开发过程(Scrum) 第二天 ...
- Windows窗体控件实现内容拖放(DragDrop)功能
一.将控件内容拖到其他控件 在开发过程中,经常会有这样的要求,拖动一个控件的数据到另外一个控件中.例如将其中一个ListBox中的数据拖到另一个ListBox中.或者将DataGridView中的数据 ...
- kvm创建win7虚拟机默认只识别2个cpu解决方法
现在人在部署OpenStack之后会发现按照配额运行Linux的虚拟机没有问题,但是运行windows的虚拟机会发现如果配置2个以上的核则无法识别,windows server也最多支持到4个核.无法 ...