• 用java手写了个JSON解析&生成器


    同步:https://zhufn.fun/archives/handwritejson/
    主要实现思路是递归。我们把单个值也当作合法的json,先判断当前json类型,如果是单个值就直接return对应类型(解析时)或toString(编码时),如果是Object就遍历它的key值,然后取冒号后面的部分递归解析/编码,Array也差不多。
    经解码再编码测试非常完美。
    img

    知识点:java泛型类如HashMap<String, Object>无法用instanceof检测。
    但是,可以新写一个空类去继承他,这样就不是泛型了。

    (Java快加个rust那种枚举吧)

    Warning有点多,将就看

    package fun.zhufn.oldcomm;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    class BadJsonException extends RuntimeException {
    }
    
    class JsonMap extends HashMap<String, Object> {
    
    }
    
    class JsonList extends ArrayList<Object> {
    
    }
    
    public class MyJsonParser {
        static void print(String s) {
            System.out.println(s);
        }
    
        public static void writeToFile(String path, Object data) throws Exception{
            File f = new File(path);
            FileOutputStream fs = new FileOutputStream(f);
            fs.write(gen(data).getBytes());
            fs.close();
        }
    
        public static Object parse(String json) throws BadJsonException {
            json = json.trim();
            if (json.startsWith("[") && json.endsWith("]")) {
                JsonList ret = new JsonList();
                json = json.substring(1, json.length() - 1);
                while(true) {
                    int p1 = 0, p2 = findNextComma(json), len = json.length();
                    String curLine = json.substring(p1, p2).trim();
                    if (curLine.isEmpty()) break;
                    ret.add(parse(curLine));
    
                    if (p2 < len) json = json.substring(p2 + 1);
                    else break;
                }
                return ret;
            } else if (json.startsWith("{") && json.endsWith("}")) {
                return nextObject(json);
            } else if (json.startsWith("\"") && json.endsWith("\"")) {
                int cnt = 0;
                for (int i = 0; i < json.length(); ++i) {
                    if (json.charAt(i) == '"' && (i > 0 && json.charAt(i - 1) != '\\')) {
                        ++cnt;
                    }
                }
                if (cnt > 2) throw new BadJsonException();
                return json.substring(1, json.length() - 1);
            } else if (json.equals("true")) {
                return true;
            } else if (json.equals("false")) {
                return false;
            } else {
                try {
                    return Double.parseDouble(json);
                } catch (Exception e) {
                    throw new BadJsonException();
                }
            }
        }
    
        private static JsonMap nextObject(String json) throws BadJsonException {
            JsonMap ret = new JsonMap();
            if (!json.startsWith("{") || !json.endsWith("}")) {
                throw new BadJsonException();
            }
            json = json.substring(1, json.length() - 1).trim();
            if (json.isEmpty()) return ret;
            while(true) {
                int p1 = 0, p2 = findNextComma(json), len = json.length();
                String curLine = json.substring(p1, p2).trim();
                if (curLine.startsWith("\"")) {
                    int j = stringPos(curLine);
                    String key = curLine.substring(1, j);
                    curLine = curLine.substring(j + 1).trim();
                    if (!curLine.startsWith(":")) throw new BadJsonException();
                    ret.put(key, parse(curLine.substring(1).trim()));
                } else {
                    throw new BadJsonException();
                }
                if (p2 < len) json = json.substring(p2 + 1);
                else break;
            }
            return ret;
        }
    
        private static int intPos(String str) throws BadJsonException {
            int i = -1;
            while (i + 1 < str.length() &&str.charAt(i + 1) >= '0' && str.charAt(i + 1) <= '9') {
                ++i;
            }
            if (i == -1) {
                throw new BadJsonException();
            }
            return i;
        }
    
        private static int stringPos(String str) throws BadJsonException {
            if (!str.startsWith("\"")) {
                throw new BadJsonException();
            }
            int i = 1;
            while (i < str.length()) {
                if (str.charAt(i) == '"') {
                    break;
                }
                ++i;
            }
            if (i == str.length()) throw new BadJsonException();
            return i;
        }
    
        private static int findNextComma(String json) throws BadJsonException {
            int quoteCnt = 0, squareBracketsCnt = 0, bracesCnt = 0;
            int len = json.length();
            int i = 0;
            while (i < len) {
                if (json.charAt(i) == ',' && quoteCnt % 2 == 0 && squareBracketsCnt == 0 && bracesCnt == 0) {
                    break;
                }
                if (json.charAt(i) == '"') {
                    ++quoteCnt;
                }
                if (json.charAt(i) == '[') {
                    ++squareBracketsCnt;
                }
                if (json.charAt(i) == '{') {
                    ++bracesCnt;
                }
                if (json.charAt(i) == ']') {
                    --squareBracketsCnt;
                }
                if (json.charAt(i) == '}') {
                    --bracesCnt;
                }
                ++i;
            }
            return i;
        }
    
        public static String gen(Object data) {
            if (data instanceof JsonMap) {
                StringBuilder ret = new StringBuilder("{");
                JsonMap mp = (JsonMap)data;
                for (String key: mp.keySet()) {
                    ret.append("\"").append(key).append("\":");
                    ret.append(gen(mp.get(key)));
                    ret.append(",");
                }
                if(ret.charAt(ret.length() - 1) == ',') ret.delete(ret.length() - 1, ret.length());
                ret.append("}");
                return ret.toString();
            } else if (data instanceof JsonList) {
                StringBuilder ret = new StringBuilder("[");
                for (Object v: (JsonList)data) {
                    ret.append(gen(v));
                    ret.append(",");
                }
                if(ret.charAt(ret.length() - 1) == ',') ret.delete(ret.length() - 1, ret.length());
                ret.append("]");
                return ret.toString();
            } else if (data instanceof String) {
                return "\"" + data + "\"";
            } else {
                return data.toString();
            }
        }
    
        public static void main(String []args) {
            //这是一组测试数据,应该没人来开我盒
            print(gen(parse("""
                    {"code":0,"message":"0","ttl":1,"data":{"isLogin":true,"email_verified":1,"face":"http://i1.hdslb.com/bfs/face/97c86ea7c397f91b1a858737d06e73859d2d86f5.jpg","face_nft":0,"level_info":{"current_level":6,"current_min":28800,"current_exp":31365,"next_exp":"--"},"mid":39100231,"mobile_verified":1,"money":85,"moral":70,"official":{"role":0,"title":"","desc":"","type":-1},"officialVerify":{"type":-1,"desc":""},"pendant":{"pid":6053,"name":"星尘","image":"http://i1.hdslb.com/bfs/garb/item/92d63a9014d4f0b2cefaef64f757162f750c7ad0.png","expire":0,"image_enhance":"http://i1.hdslb.com/bfs/garb/item/92d63a9014d4f0b2cefaef64f757162f750c7ad0.png","image_enhance_frame":""},"scores":0,"uname":"BuringStraw","vipDueDate":1668355200000,"vipStatus":1,"vipType":2,"vip_pay_type":0,"vip_theme_type":0,"vip_label":{"path":"","text":"年度大会员","label_theme":"annual_vip","text_color":"#FFFFFF","bg_style":1,"bg_color":"#FB7299","border_color":""},"vip_avatar_subscript":1,"vip_nickname_color":"#FB7299","vip":{"type":2,"status":1,"due_date":1668355200000,"vip_pay_type":0,"theme_type":0,"label":{"path":"","text":"年度大会员","label_theme":"annual_vip","text_color":"#FFFFFF","bg_style":1,"bg_color":"#FB7299","border_color":""},"avatar_subscript":1,"nickname_color":"#FB7299","role":3,"avatar_subscript_url":"http://i0.hdslb.com/bfs/vip/icon_Certification_big_member_22_3x.png"},"wallet":{"mid":39100231,"bcoin_balance":1,"coupon_balance":0,"coupon_due_time":0},"has_shop":false,"shop_url":"","allowance_count":0,"answer_status":0,"is_senior_member":1}}""")));
        }
    }
    
    
  • 相关阅读:
    maven 设置日志级别
    浏览器工作原理:浅析浏览器中的页面
    浏览器工作原理:浅析浏览器中的页面
    解决uniapp的websocket连接在web和安卓正常,iOS连接不上的问题
    浏览器工作原理:浅析页面循环系统
    浏览器工作原理:浅析页面循环系统
    浏览器工作原理:浅析页面循环系统
    浅析如何使用WebSocket、SockJS、STOMP实现消息实时通讯功能:websocket/SocketJS/Stomp是什么及三者的关系、stomp协议格式、如何开启stomp、如何处理客服端发送的stomp、如何发消息给客服端、如何在任何地方发消息、如何给目标或指定用户发消息
    解决sockjs、stomp在uni-app端使用的坑
    浏览器工作原理:浅析页面循环系统
  • 原文地址:https://www.cnblogs.com/buringstraw/p/16279308.html
Copyright © 2020-2023  润新知