【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

posted @   逆火狂飙  阅读(275)  评论(1编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
生当作人杰 死亦为鬼雄 至今思项羽 不肯过江东
点击右上角即可分享
微信分享提示