【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程序 ...
随机推荐
- Android笔记(五十三) 利用有道OPENAPI做简单的翻译demo
先去 http://fanyi.youdao.com/openapi?path=data-mode 申请开发者key 有道api会自动将申请的单词翻译并返回为xml或者json格式,我们所需要做的就是 ...
- python中csv模块和join函数的使用
在看项目的时候恰好又碰到了这两个功能,然后稍微记录一下,关于join函数,是一个经常使用的联合函数,作用就是用自己规定的字符去串联字符串和列表之类的,对于字符串来说,join函数针对的是字符串中的每一 ...
- ansible之基础篇(三)
setup ansible_all_ipv4_addresses # ipv4的所有地址 ansible_all_ipv6_addresses # ipv6的所有地址 ansible_date_tim ...
- idea中添加web.xml配置文件与tomcat启动中遇到的web.xml文件找不到的问题
1,如何在idea中向war项目中添加web.xml的配置文件 idea通过maven创建war项目时没有指定是webapp导致创建出来的项目没有webapp的文件夹.其实war项目中都是在" ...
- HTML&CSS基础-伪类选择器
HTML&CSS基础-伪类选择器 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.html源代码 <!DOCTYPE html> <html> & ...
- git修改提交历史中的author信息
当次提交 当次的提交显示指定提交者信息: git commit -m "Initial commit" --author="mn <mn@furzoom.com&g ...
- java加密算法-MD5
import java.security.MessageDigest; public class MD5Util { /*** * MD5加密 生成32位md5码 * @param 待加密字符串 * ...
- Linux关闭防火墙、设置端口
关闭防火墙 1)重启后生效 开启: chkconfig iptables on 关闭: chkconfig iptables off 验证防火墙是否关闭:chkconfig --list |grep ...
- Spark-2.3.2 Java SparkSQL的自定义HBase数据源
由于SparkSQL不支持HBase的数据源(HBase-1.1.2),网上有很多是采用Hortonworks的SHC,而SparkSQL操作HBase自定义数据源大多数都是基于Scala实现,我就自 ...
- Multiple declaration for 'fd_set'
如果程序编译时报 [C++ Error] winsock2.h(109): E2238 Multiple declaration for 'fd_set' 这样的错误,可以尝试在,winsock2.h ...