JAVA校验JSON数据格式

在此博文基础上增添了更多校验功能https://blog.csdn.net/weixin_42540829/article/details/88326880

   public static final class RouteTableJsonValidator {

        /**
         * 数组指针
         */
        private static int index;
        /**
         * 字符串
         */
        private static String value;
        /**
         * 指针当前字符
         */
        private static char curchar;

        /**
         * 工具类非公有构造函数
         */
        private RouteTableJsonValidator() {
        }

        /**
         * @param rawValue 字符串参数
         * @return boolean 是否是JSON
         */
        public static boolean isJSON(String rawValue) throws Exception {
                index = 0;
                value = rawValue;
                switch (nextClean()) {
                    case '[':
                        if (nextClean() == ']') {
                            return true;
                        }
                        back();
                        return validateArray();
                    case '{':
                        if (nextClean() == '}') {
                            return true;
                        }
                        back();
                        return validateObject();
                    default:
                        return false;
                }
        }

        /**
         * @return char 下一个有效实义字符 char<=' ' char!=127
         * @throws JSONException 自定义JSON异常
         */
        public static char nextClean() throws JSONException {
            skipComment:
            do {
                next();
                if (curchar == '/') { // 跳过//类型与/*类型注释 遇回车或者null为注释内容结束
                    switch (next()) {
                        case 47: // '/'
                            do {
                                curchar = next();
                            } while (curchar != '\n' && curchar != '\r' && curchar != 0);
                            continue;
                        case 42: // '*'
                            do {
                                do {
                                    next();
                                    if (curchar == 0) {
                                        throw syntaxError("Unclosed comment");
                                    }
                                } while (curchar != '*');
                                if (next() == '/') {
                                    continue skipComment;
                                }
                                back();
                            } while (true);
                    }
                    back();
                    return '/';
                }
                if (curchar != '#') { //跳过#类型注释 遇回车或者null为注释内容结束
                    break;
                }
                do {
                    next();
                } while (curchar != '\n' && curchar != '\r' && curchar != 0);
            } while (true);
            if (curchar != 0 && (curchar <= ' ' || curchar == 127)) {
                throw syntaxError("JSON can not contain control character!");
            }
            return curchar;
        }

        /**
         * @return char 下一个字符
         */
        public static char next() {
            if (index < 0 || index >= value.length()) {
                return '\0';
            }
            curchar = value.charAt(index);
            if (curchar <= 0) {
                return '\0';
            } else {
                index++;
                return curchar;
            }
        }

        /**
         * 将指针移至上一个字符,回退一位
         */
        public static void back() { //异常在next中进行返回null
            index--;
        }

        /**
         * @param message 异常自定义信息
         * @return JSONException 自定义JSON异常
         */
        public static JSONException syntaxError(String message) {
            return new JSONException((new StringBuilder(String.valueOf(message))).toString());
        }

        /**
         * @return boolean 是否是JSONArray
         * @throws JSONException 自定义JSON异常
         */
        public static boolean validateArray() throws JSONException {
            do {
                //入口为合法 [ array 起点
                nextClean(); //下一位有效字符,跳过注释
                if (curchar == ']') { //空array 直接闭合返回
                    return true;
                } else if (curchar == ',') { //null
                    continue;
                } else if (curchar == '"') { //String
                    validateString();
                } else if (curchar == '-' || (curchar >= 48 && curchar <= 57)) { // number
                    validateNumber();
                } else if (curchar == '{') { // object
                    if (!validateObject()) { //递归校验
                        return false;
                    }
                } else if (curchar == '[') { // array
                    if (!validateArray()) { //递归校验
                        return false;
                    }
                } else if (curchar == 't' || curchar == 'f' || curchar == 'n') { // boolean and JSONNull
                    validateBooleanAndNull();
                } else {
                    return false;
                }
                switch (nextClean()) {
                    case ',':
                        continue;
                    case ']':
                        return true;
                    default:
                        return false;
                }
            } while (true);
        }

        /**
         * @return boolean 是否是JSONObject
         * @throws JSONException 自定义JSON异常
         */
        public static boolean validateObject() throws JSONException {
            do {
                nextClean();
                if (curchar == '}') {
                    return true;
                } else if (curchar == '"') { //String
                    validateString();
                } else {
                    return false;
                }
                if (nextClean() != ':') {
                    return false;
                }
                nextClean();
                if (curchar == ',') { //null
                    throw syntaxError("Missing value");
                } else if (curchar == '"') { //String
                    validateString();
                } else if (curchar == '-' || (curchar >= 48 && curchar <= 57)) { // number
                    validateNumber();
                } else if (curchar == '{') { // object
                    if (!validateObject()) {
                        return false;
                    }
                } else if (curchar == '[') { // array
                    if (!validateArray()) {
                        return false;
                    }
                } else if (curchar == 't' || curchar == 'f' || curchar == 'n') { // boolean and JSONNull
                    validateBooleanAndNull();
                } else {
                    return false;
                }
                switch (nextClean()) {
                    case ',':
                        continue;
                    case '}':
                        return true;
                    default:
                        return false;
                }
            } while (true);
        }

        /**
         * @throws JSONException 自定义JSON异常
         */
        public static void validateString() throws JSONException {
            StringBuilder sb = new StringBuilder();
            do {
                curchar = next(); //JSON对字符串中的转义项有严格规定
                sb.append(curchar);
                if (curchar == '\\') {
                    if ("\"\\/bfnrtu".indexOf(next()) < 0) {
                        throw syntaxError("Invalid escape string");
                    }
                    if (curchar == 'u') { //校验unicode格式 后跟4位16进制 0-9 a-f A-F
                        for (int i = 0; i < 4; i++) {
                            next();
                            if (curchar < 48 || (curchar > 57 && curchar < 65) || (curchar > 70 && curchar < 97)
                                    || curchar > 102) {
                                throw syntaxError("Invalid hexadecimal digits");
                            }
                        }
                    }
                }
            } while (curchar >= ' ' && "\":{[,#/".indexOf(curchar)< 0 && curchar != 127);
            if (curchar == 0) { //仅正常闭合双引号可通过
                throw syntaxError("Unclosed quot");
            } else if (curchar != '"') {
                throw syntaxError("Invalid string {\""+ sb +"}, missing quot ");
            } else if (value.charAt(index)=='"') {
                throw syntaxError("Missing comma after string: \"" + sb);
            } else if (value.charAt(index)==':' ) {
                String str = sb.substring(0, sb.length() - 1);
//                if (!validateRouteTableKey(sb.charAt(0), str)) {
//                    throw syntaxError("Invalid RouteTable KEY:\"" + sb);
//                }
                validateRouteTableValue(str);
            }
        }

        /**
         * @throws JSONException 自定义JSON异常
         */
        public static void validateNumber() throws JSONException {
            StringBuilder sb = new StringBuilder();
            if (curchar == '-') { //可选负号
                curchar = next();
            }
            if (curchar > 48 && curchar <= 57) { //整数部分
                do {
                    sb.append(curchar);
                    curchar = next();
                } while (curchar >= 48 && curchar <= 57);
            } else if (curchar == 48) {
                curchar = next();
            } else {
                throw syntaxError("Invalid number");
            }
            if (curchar == '.') { //小数部分
                do { //.后可不跟数字 如 5. 为合法数字
                    curchar = next();
                } while (curchar >= 48 && curchar <= 57);
            }
            if (curchar == 'e' || curchar == 'E') { //科学计数部分
                curchar = next();
                if (curchar == '+' || curchar == '-') {
                    curchar = next();
                }
                if (curchar < 48 || curchar > 57) {
                    throw syntaxError("Invalid number");
                }
                do {
                    curchar = next();
                } while (curchar >= 48 && curchar <= 57);
            }
            if (curchar == '"') {
                throw syntaxError("Missing comma after number: " + sb);
            }
            back(); //指针移至数字值最后一位,取下一位即判断是,或者],或者是合法注释
        }

        public static void validateRouteTableValue(String key) throws JSONException {
            int a = index;
            char c,d ;
            List<String> num_list = Arrays.asList("port");
            List<String> boolean_list = Arrays.asList("useSSL", "default_allow");
            do {
                ++a;
                c = value.charAt(a);
            } while (c == ' ' || c == '"');

            StringBuilder sb = new StringBuilder();
            do {
                d = value.charAt(a);
                sb.append(d);
                a++;
            } while (d !=' ' && ",]}\"".indexOf(d) <0);
            String str = sb.substring(0,sb.length()-1);

            if (num_list.contains(key) && !(c == '-' || (c >= 48 && c <= 57))) {
                throw syntaxError("RouteTable KEY:" + key + " match NumberType");
            }
            if (boolean_list.contains(key) && !(c == 't' || c == 'f' || c == 'n')) {
                throw syntaxError("RouteTable KEY:" + key + " match BooleanType");
            }
            String port_reg = "^([0-5]?\\d{0,4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])$";
            if("port".equals(key) && !str.matches(port_reg)){
                throw syntaxError("Invalid Port : " + str);
            }
            String ip_reg = "^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$";
            if("ip".equals(key) && !str.matches(ip_reg)){
                throw syntaxError("Invalid ip : " + str);
            }
        }

        public static boolean validateRouteTableKey(char firstChar, String str) throws JSONException {
            if ("".equals(str)) return false;
            List<String> a_list = Arrays.asList("allow");
            List<String> c_list = Arrays.asList("certChainFile","caFile","coordinator");
            List<String> d_list = Arrays.asList("default", "default_allow","deny");
            List<String> f_list = Arrays.asList("from");
            List<String> h_list = Arrays.asList("host");
            List<String> i_list = Arrays.asList("ip");
            List<String> n_list = Arrays.asList("negotiationType","caFile");
            List<String> p_list = Arrays.asList("permission", "port", "privateKeyFile");
            List<String> r_list = Arrays.asList("route_table","role");
            List<String> s_list = Arrays.asList("serving");
            List<String> t_list = Arrays.asList("to");
            List<String> u_list = Arrays.asList("useSSL");
            switch (firstChar) {
                case ' ':
                    return false;
                case 'a':
                    return a_list.contains(str);
                case 'f':
                    return f_list.contains(str);
                case 't':
                    return t_list.contains(str);
                case 'i':
                    return i_list.contains(str);
                case 'h':
                    return h_list.contains(str);
                case 's':
                    return s_list.contains(str);
                case 'u':
                    return u_list.contains(str);
                case 'c':
                    return c_list.contains(str);
                case 'n':
                    return n_list.contains(str);
                case 'r':
                    return r_list.contains(str);
                case 'd':
                    return d_list.contains(str);
                case 'p':
                    return p_list.contains(str);
                default:
                    return true;
            }

        }

        /**
         * @throws JSONException 自定义JSON异常
         */
        public static void validateBooleanAndNull() throws JSONException {
            StringBuilder sb = new StringBuilder();
            do {
                sb.append(curchar);
                curchar = next();
            } while (curchar >= ' ' && "\",]#/}".indexOf(curchar) < 0 && curchar != 127);
            if (!"null".equals(sb.toString()) && !"true".equals(sb.toString()) && !"false".equals(sb.toString())) {
                throw syntaxError("Boolean/null spelling errors : " + sb);
            }
            if (curchar == '"') {
                throw syntaxError("Missing comma after Boolean: " + sb);
            }
            back();
        }
    }

    public static void main(String[] args) {
//        String str = "{\"route_table\": {\"default\":{\"default\":[{\"ip\":\"127.0.0.1\",\"port\":9999,\"useSSL\":false}]},\"10000\":{\"default\":[{\"ip\":\"127.0.0.1\",\"port\":8889}],\"serving\":[{\"ip\":\"127.0.0.1\",\"port\":8080}]},\"123\":[{\"host\":\"10.35.27.23\",\"port\":8888,\"useSSL\":false,\"negotiationType\":\"\",\"certChainFile\":\"\",\"privateKeyFile\":\"\",\"caFile\":\"\"}]},\"permission\":{\"default_allow\":true}}";
        String str = "{\"route_table\":{\"default\":{\"default\":[{\"ip\":\"127.0.0.1\",\"port\":2345}]},\"10000\":{\"default\":[{\"ip\":\"127.0.0.1\",\"port\":8889}],\"serving\":[{\"ip\":\"127.0.0.1\",\"port\":8080}]}},\"permission\":{\"default_allow\":true,\"allow\":[{\"from\":{\"coordinator\":\"9999\",\"role\":\"guest\"},\"to\":{\"coordinator\":\"10000\",\"role\":\"host\"}}],\"deny\":[{\"from\":{\"coordinator\":\"9999\",\"role\":\"guest\"},\"to\":{\"coordinator\":\"10000\",\"role\":\"host\"}}]}}";
        try {
            if (RouteTableJsonValidator.isJSON(str)) {
                String s = JsonUtil.formatJson(str);
                System.out.println(s);
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

热门文章

暂无图片
编程学习 ·

Java输出数组的内容

Java输出数组的内容_一万个小时-CSDN博客_java打印数组内容1. 输出内容最常见的方式// List<String>类型的列表List<String> list new ArrayList<String>();list.add("First");list.add("Second");list.add("Third");list.ad…
暂无图片
编程学习 ·

母螳螂的“魅惑之术”

在它们对大蝗虫发起进攻的时候&#xff0c;我认认真真地观察了一次&#xff0c;因为它们突然像触电一样浑身痉挛起来&#xff0c;警觉地面对限前这个大家伙&#xff0c;然后放下自己优雅的身段和祈祷的双手&#xff0c;摆出了一个可怕的姿势。我被眼前的一幕吓到了&#xff0c;…
暂无图片
编程学习 ·

疯狂填词 mad_libs 第9章9.9.2

#win7 python3.7.0 import os,reos.chdir(d:\documents\program_language) file1open(.\疯狂填词_d9z9d2_r.txt) file2open(.\疯狂填词_d9z9d2_w.txt,w) words[ADJECTIVE,NOUN,VERB,NOUN] str1file1.read()#方法1 for word in words :word_replaceinput(fEnter a {word} :)str1…
暂无图片
编程学习 ·

HBASE 高可用

为了保证HBASE是高可用的,所依赖的HDFS和zookeeper也要是高可用的. 通过参数hbase.rootdir指定了连接到Hadoop的地址,mycluster表示为Hadoop的集群. HBASE本身的高可用很简单,只要在一个健康的集群其他节点通过命令 hbase-daemon.sh start master启动一个Hmaster进程,这个Hmast…
暂无图片
编程学习 ·

js事件操作语法

一、事件的绑定语法 语法形式1 事件监听 标签对象.addEventListener(click,function(){}); 语法形式2 on语法绑定 标签对象.onclick function(){} on语法是通过 等于赋值绑定的事件处理函数 , 等于赋值本质上执行的是覆盖赋值,后赋值的数据会覆盖之前存储的数据,也就是on…
暂无图片
编程学习 ·

Photoshop插件--晕影动态--选区--脚本开发--PS插件

文章目录1.插件界面2.关键代码2.1 选区2.2 动态晕影3.作者寄语PS是一款栅格图像编辑软件&#xff0c;具有许多强大的功能&#xff0c;本文演示如何通过脚本实现晕影动态和选区相关功能&#xff0c;展示从互联网收集而来的一个小插件&#xff0c;供大家学习交流&#xff0c;请勿…
暂无图片
编程学习 ·

vs LNK1104 无法打开文件“xxx.obj”

写在前面&#xff1a; 向大家推荐两本新书&#xff0c;《深度学习计算机视觉实战》和《学习OpenCV4&#xff1a;基于Python的算法实战》。 《深度学习计算机视觉实战》讲了计算机视觉理论基础&#xff0c;讲了案例项目&#xff0c;讲了模型部署&#xff0c;这些项目学会之后可以…
暂无图片
编程学习 ·

工业元宇宙的定义与实施路线图

工业元宇宙的定义与实施路线图 李正海 1 工业元宇宙 给大家做一个关于工业元宇宙的定义。对于工业&#xff0c;从设计的角度来讲&#xff0c;现在的设计人员已经做到了普遍的三维设计&#xff0c;但是进入元宇宙时代&#xff0c;就不仅仅只是三维设计了&#xff0c;我们的目…
暂无图片
编程学习 ·

【leectode 2022.1.15】完成一半题目

有 N 位扣友参加了微软与力扣举办了「以扣会友」线下活动。主办方提供了 2*N 道题目&#xff0c;整型数组 questions 中每个数字对应了每道题目所涉及的知识点类型。 若每位扣友选择不同的一题&#xff0c;请返回被选的 N 道题目至少包含多少种知识点类型。 示例 1&#xff1a…
暂无图片
编程学习 ·

js 面试题总结

一、js原型与原型链 1. prototype 每个函数都有一个prototype属性&#xff0c;被称为显示原型 2._ _proto_ _ 每个实例对象都会有_ _proto_ _属性,其被称为隐式原型 每一个实例对象的隐式原型_ _proto_ _属性指向自身构造函数的显式原型prototype 3. constructor 每个prot…
暂无图片
编程学习 ·

java练习代码

打印自定义行数的空心菱形练习代码如下 import java.util.Scanner; public class daYinLengXing{public static void main(String[] args) {System.out.println("请输入行数");Scanner myScanner new Scanner(System.in);int g myScanner.nextInt();int num g%2;//…
暂无图片
编程学习 ·

RocketMQ-什么是死信队列?怎么解决

目录 什么是死信队列 死信队列的特征 死信消息的处理 什么是死信队列 当一条消息初次消费失败&#xff0c;消息队列会自动进行消费重试&#xff1b;达到最大重试次数后&#xff0c;若消费依然失败&#xff0c;则表明消费者在正常情况下无法正确地消费该消息&#xff0c;此时…
暂无图片
编程学习 ·

项目 cg day04

第4章 lua、Canal实现广告缓存 学习目标 Lua介绍 Lua语法 输出、变量定义、数据类型、流程控制(if..)、循环操作、函数、表(数组)、模块OpenResty介绍(理解配置) 封装了Nginx&#xff0c;并且提供了Lua扩展&#xff0c;大大提升了Nginx对并发处理的能&#xff0c;10K-1000K Lu…
暂无图片
编程学习 ·

输出三角形

#include <stdio.h> int main() { int i,j; for(i0;i<5;i) { for(j0;j<i;j) { printf("*"); } printf("\n"); } }
暂无图片
编程学习 ·

stm32的BOOTLOADER学习1

序言 最近计划学习stm32的BOOTLOADER学习,把学习过程记录下来 因为现在网上STM32C8T6还是比较贵的,根据我的需求flash空间小一些也可以,所以我决定使用stm32c6t6.这个芯片的空间是32kb的。 #熟悉芯片内部的空间地址 1、flash ROM&#xff1a; 大小32KB&#xff0c;范围&#xf…
暂无图片
编程学习 ·

通过awk和shell来限制IP多次访问之学不会你打死我

学不会你打死我 今天我们用shell脚本&#xff0c;awk工具来分析日志来判断是否存在扫描器来进行破解网站密码——限制访问次数过多的IP地址&#xff0c;通过Iptables来进行限制。代码在末尾 首先我们要先查看日志的格式&#xff0c;分析出我们需要筛选的内容&#xff0c;日志…
暂无图片
编程学习 ·

Python - 如何像程序员一样思考

在为计算机编写程序之前&#xff0c;您必须学会如何像程序员一样思考。学习像程序员一样思考对任何学生都很有价值。以下步骤可帮助任何人学习编码并了解计算机科学的价值——即使他们不打算成为计算机科学家。 顾名思义&#xff0c;Python经常被想要学习编程的人用作第一语言…
暂无图片
编程学习 ·

蓝桥杯python-数字三角形

问题描述 虽然我前后用了三种做法&#xff0c;但是我发现只有“优化思路_1”可以通过蓝桥杯官网中的测评&#xff0c;但是如果用c/c的话&#xff0c;每个都通得过&#xff0c;足以可见python的效率之低&#xff08;但耐不住人家好用啊&#xff08;哭笑&#xff09;&#xff09…