下载地址: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. Android笔记(六十七) 自定义控件

    实际编程中,系统提供的控件往往无法满足我们的需求,一来是样子丑陋,二来是一些复杂的组合需要多次使用的话,每次都写一堆控件的组合会很耗费时间,所以我们将这些组件的组合自定义为一个新的控件,以后使用的时候 ...

  2. Java异常类的继承关系图

  3. zabbix Server 4.0 监控TCP的12种状态

      zabbix Server 4.0 监控TCP的12种状态 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 大家对TCP三次握手比较熟悉了,都知道当发生DOSS攻击时,客户端发送 ...

  4. tornado项目工程

    项目模块基本架构如下: -------------application.py import tornado.web from views import index, login import con ...

  5. 微信小程序API~用户信息

    UserInfo 用户信息 属性 string nickName 用户昵称 string avatarUrl 用户头像图片的 URL.URL 最后一个数值代表正方形头像大小(有 0.46.64.96. ...

  6. Hdfs读写数据出错

    1.Hdfs读数据出错:若在读数据的过程中,客户端和DataNode的通信出现错误,则会尝试连接下一个 包含次文件块的DataNode.同时记录失败的DataNode,此后不再被连接. 2.Hdfs在 ...

  7. GDB十分钟教程【转载于网络爱好者】

    本文写给主要工作在Windows操作系统下而又需要开发一些跨平台软件的程序员朋友,以及程序爱好者. GDB是一个由GNU开源组织发布的.UNIX/LINUX操作系统下的.基于命令行的.功能强大的程序调 ...

  8. 自行撰写Grasshopper电池

    Grasshopper目前作为参数化设计是非常常用的工具,但是人们会经常碰到它提供的电池不能满足自己设计方案需求的情况,所以就需要自己创作电池,而最简单的一种方法就是自己写. 工具: Visual S ...

  9. Linux 系统安装下安装 mysql5.7(glibc版)

    转自:https://www.cnblogs.com/mujingyu/p/7689116.html 前言:经过一天半的折腾,终于把 mysql 5.7.17 版本安装上了 centos 7 系统上, ...

  10. golang-切片copy

    package main import ( "fmt" ) func main() { fmt.Println("-------------") data := ...