下载地址: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文进行内部整形排序后再输出的更多相关文章

  1. 【json/regex】将简单对象生成的json文进行内部排序后再输出

    有这样一个实体类: package com.hy; public class Emp { private int id; private int age; private String name; p ...

  2. 做一次面向对象的体操:将JSON字符串转换为嵌套对象的一种方法

    背景与问题 在 <一个略复杂的数据映射聚合例子及代码重构> 一文中,将一个JSON字符串转成了所需要的订单信息Map.尽管做了代码重构和配置化,过程式的代码仍然显得晦涩难懂,并且客户端使用 ...

  3. ObjC 利用反射和KVC实现嵌套对象序列化成JSON数据

    原理: 0.创建一个新的可变字典:NSMutableDictionary 1.采用class_copyPropertyList函数遍历对象的属性 2.property_getName获取属性名,val ...

  4. C# json提取多层嵌套到数组-- C# json 数组

    json比一般格式再复杂点的就像数组一样,有多层嵌套,研究了一下,记录代码如下: string jsonText = "{'name':'test','phone':'18888888888 ...

  5. java对象转化为json字符串并传到前台

    package cc.util; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import ...

  6. Json对象与Json字符串的转化、JSON字符串与Java对象的转换

    一.Json对象与Json字符串的转化 1.jQuery插件支持的转换方式: $.parseJSON( jsonstr ); //jQuery.parseJSON(jsonstr),可以将json字符 ...

  7. 【Python】将对象存成json文件及从json取出对象

    常用代码,单拎出来以备查. 对象存json文件: import json obj={'name':'张有财','age':39,'arr':[2,34,5,6,7,88,'李有钱']} with op ...

  8. Json对象与Json字符串的转化、JSON字符串与Java对象的转换(转)

    一.Json对象与Json字符串的转化 1.jQuery插件支持的转换方式: $.parseJSON( jsonstr ); //jQuery.parseJSON(jsonstr),可以将json字符 ...

  9. JSON字符串和Javascript对象字面量

    JSON字符串和Javascript对象字面量 JSON是基于Javascript语法的一个子集而创建的,特别是对象和数组字面量语法. 正是由于JSON的这种特殊来历,导致很多Javascript程序 ...

随机推荐

  1. 【转】TI DSP C6657学习之——编译静态库.lib

    熟悉C++开发的的小伙伴都知道,我们一般代码中往往要引入许多第三方编译好的库,有些是静态链接库static library, 有些是动态链接库dll.引入库的目的一是减少代码的编译时间,二是只提供函数 ...

  2. 开发环境wamp3.06 + Zend studio 12 调试配置

    <?php $fileName = "php大师.test.php"; //补充程序,显示文件名(不包括扩展名) $start = strrpos($fileName, &q ...

  3. pyserial 挺强大的

    Ref: https://pythonhosted.org/pyserial/ pyserial写的很规范,无论安装和使用都非常的容易,目前使用下来非常好. 没有使用它做过压力测试,不知道表现如何. ...

  4. Vue中mapMutations映射方法的问题

    今天又被自己给蠢到,找了半天没发现问题.大家看下代码. mutation-types.js 里我新增了一个类型.INIT_CURRENTORDER export const GET_USERINFO ...

  5. 如何在linux环境下配置环境变量

    jdk下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 在linux环 ...

  6. 双向认证下rpc-gateway使用(同时提供rpc和http服务)

    下载go get -v github.com/grpc-ecosystem/grpc-gateway,然后把这个包下面的third-party下面的google文件夹拷贝到Prod.proto的同级目 ...

  7. Canvas 总结,到第4章 canvas图形变换

    canvas 必须认识到的大坑 <!-- 重点: 在js/canvas标签中定义的宽和高是画布实际的宽和高. 在样式表中定义的宽和高是画布缩放后的宽和高. 即:把js/canvas实际大小缩放到 ...

  8. javaweb学习笔记(二)

    一.javaweb学习是所需要的细节 1.Cookie的注意点 ① Cookie一旦创建,它的名称就不能更改,Cookie的值可以为任意值,创建后允许被修改. ② 关于Cookie中的setMaxAg ...

  9. HTML 009 select

    本篇文章并非描述HTML中的select标签, 而是描述JSP中的<s:select> 关于HTML中的select标签, 以及和JSP中的<s:select>的相同以及差异后 ...

  10. Spring入门(四)——整合Mybatis

    1. 准备jar包及目录结构 2. 配置db.properties driver = com.mysql.jdbc.Driver url = jdbc:mysql://127.0.0.1:3306/H ...