首页 > 编程语言 >json解析源码学习

json解析源码学习

时间:2023-08-13 09:22:27浏览次数:43  
标签:case return TOKEN private break json 源码 解析

c#的几个Json库

MiniJSON

SimpleJson

litjson

NewtonJson

 

其中MiniJSON最简单,所以这边也是学习这个库的Json解析部分(注意:只涉及解析,没有生成json)。

整体代码也没有用到特别的算法什么的,就是一个一个字符的读取,然后根据读到的边界标识符来进行后续的读取,边界标识符的话就是:{}、[]、""、:、,等。

单引号、注释这些的话没有支持,加上各种兼容性估计代码就会复杂很多。

/*
 * http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html
 *
 * Simplified it so that it doesn't throw exceptions
 * and can be used in Unity iPhone with maximum code stripping.
 *
 */
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;

public static class Json
{
    /// <summary>
    /// Parses the string json into a value
    /// </summary>
    /// <param name="json">A JSON string.</param>
    /// <returns>An List&lt;object&gt;, a Dictionary&lt;string, object&gt;, a double, an integer,a string, null, true, or false</returns>
    public static object Deserialize(string json)
    {
        if (json == null)
            return null;
        return Parser.Parse(json);
    }


    private sealed class Parser : IDisposable
    {
        private const string WORD_BREAK = "{}[],:\"";
        private StringReader json;

        private Parser(string jsonString)
        {
            json = new StringReader(jsonString);
        }

        /// <summary>
        /// 探查下一个字符(读指针不变)
        /// </summary>
        private char PeekChar
        {
            get { return Convert.ToChar(json.Peek()); }
        }

        /// <summary>
        /// 读下一个字符(读指针往后+1)
        /// </summary>
        private char NextChar
        {
            get { return Convert.ToChar(json.Read()); }
        }

        private string NextWord
        {
            get
            {
                var word = new StringBuilder();

                while (!IsWordBreak(PeekChar))
                {
                    word.Append(NextChar);

                    if (json.Peek() == -1)
                        break;
                }

                return word.ToString();
            }
        }

        /// <summary>
        /// 通过1个字符, 确定标识符, 然后以此确定接下来怎么做
        /// </summary>
        private TOKEN NextToken
        {
            get
            {
                EatWhitespace();

                if (json.Peek() == -1)
                    return TOKEN.NONE;

                switch (PeekChar)
                {
                case '{':
                    return TOKEN.CURLY_OPEN;
                case '}':
                    json.Read();
                    return TOKEN.CURLY_CLOSE;

                case '[':
                    return TOKEN.SQUARED_OPEN;
                case ']':
                    json.Read();
                    return TOKEN.SQUARED_CLOSE;

                case ',':
                    json.Read();
                    return TOKEN.COMMA;
                case '"':
                    return TOKEN.STRING;
                case ':':
                    return TOKEN.COLON;
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9':
                case '-':
                    return TOKEN.NUMBER;
                }

                switch (NextWord)
                {
                case "false":
                    return TOKEN.FALSE;
                case "true":
                    return TOKEN.TRUE;
                case "null":
                    return TOKEN.NULL;
                }

                //jsonStr="abc", 就是none的
                return TOKEN.NONE;
            }
        }

        public void Dispose()
        {
            json.Dispose();
            json = null;
        }


        /// <summary>
        /// 断词字符: abc: abc ,abc{, abc}, abc[, abc]等
        /// </summary>
        public static bool IsWordBreak(char c)
        {
            return char.IsWhiteSpace(c) || WORD_BREAK.IndexOf(c) != -1;
        }

        public static object Parse(string jsonString)
        {
            using (var instance = new Parser(jsonString))
            {
                return instance.ParseValue();
            }
        }

        private Dictionary<string, object> ParseObject()
        {
            var table = new Dictionary<string, object>();

            // ditch opening brace
            json.Read();

            // {
            while (true)
            {
                switch (NextToken)
                {
                case TOKEN.NONE:
                    // {abc} //不合法object, 得到null
                    return null;
                case TOKEN.COMMA: // {,, "key":1}也不会报错
                    continue;
                case TOKEN.CURLY_CLOSE:
                    return table;
                default:
                    // {false} //ParseString()拿到空, 然后EatWhiteSpace报错
                    // {012} // ParseString()拿到012}, 然后EatWhiteSpace报错
                    // {{}} //报错
                    // {[]} //报错

                    // name
                    var keyName = ParseString();
                    if (keyName == null)
                    {
                        return null;
                    }
                    Debug.Log($"'{keyName}'");

                    // :
                    if (NextToken != TOKEN.COLON) // {"abc"123}这样的情况, 无效的对象
                        return null;

                    // ditch the colon
                    json.Read();

                    // value
                    table[keyName] = ParseValue();
                    break;
                }
            }
        }

        private List<object> ParseArray()
        {
            var array = new List<object>();

            // ditch opening bracket
            json.Read();

            // [
            var parsing = true;
            while (parsing)
            {
                var nextToken = NextToken;

                switch (nextToken)
                {
                case TOKEN.NONE:
                    // [abc] //不合法array, 得到null
                    return null;
                case TOKEN.COMMA: // {,, 123}不会报错, 最终能得到正确的array
                    continue;
                case TOKEN.SQUARED_CLOSE:
                    parsing = false;
                    break;

                default:
                    var value = ParseByToken(nextToken);

                    array.Add(value);
                    break;
                }
            }

            return array;
        }

        //解析json的下一个值(number, bool, string, unicode, null, object, array)
        private object ParseValue()
        {
            var nextToken = NextToken;
            return ParseByToken(nextToken);
        }

        //根据开始token读后面的值
        private object ParseByToken(TOKEN token)
        {
            switch (token)
            {
            case TOKEN.STRING:
                return ParseString();
            case TOKEN.NUMBER:
                return ParseNumber();
            case TOKEN.CURLY_OPEN:
                return ParseObject();
            case TOKEN.SQUARED_OPEN:
                return ParseArray();
            case TOKEN.TRUE:
                return true;
            case TOKEN.FALSE:
                return false;
            case TOKEN.NULL:
                return null;
            default:
                return null;
            }
        }

        /// <summary>
        /// Token为STRING时, 调用该函数才正常
        /// </summary>
        private string ParseString()
        {
            var s = new StringBuilder();
            char c;

            // ditch opening quote
            json.Read();

            var parsing = true;
            while (parsing)
            {
                if (json.Peek() == -1)
                {
                    parsing = false;
                    break;
                }

                c = NextChar;
                switch (c)
                {
                case '"': //结束双引号
                    parsing = false;
                    break;

                case '\\': // 这样? { "key":"abc\
                    if (json.Peek() == -1)
                    {
                        parsing = false;
                        break;
                    }

                    c = NextChar;
                    switch (c)
                    {
                    case '"': // \"就是Append(")
                    case '\\': // \\就是Append(\)
                    case '/': // \/就是Append(/)
                        s.Append(c);
                        break;
                    case 'b':
                        s.Append('\b');
                        break;
                    case 'f':
                        s.Append('\f');
                        break;
                    case 'n':
                        s.Append('\n'); //linux换行
                        break;
                    case 'r':
                        s.Append('\r'); //mac换行
                        break;
                    case 't':
                        s.Append('\t'); //tab
                        break;
                    case 'u': // "\u012"会报错
                        var hex = new char[4];
                        for (var i = 0; i < 4; i++)
                            hex[i] = NextChar;

                        s.Append((char)Convert.ToInt32(new string(hex), 16));
                        break;
                    }
                    break;
                default:
                    s.Append(c);
                    break;
                }
            }

            Debug.Log($"ParseString: {s.ToString()}");
            return s.ToString();
        }

        private object ParseNumber()
        {
            var number = NextWord;

            // {"abc": 1-23}, 不会报错, 会得到abc的值为0
            if (number.IndexOf('.') == -1)
            {
                long parsedInt;
                long.TryParse(number, out parsedInt);
                Debug.Log($"ParseNumber: str:{number}, val:{parsedInt}");
                return parsedInt;
            }

            double parsedDouble;
            double.TryParse(number, out parsedDouble);
            Debug.Log($"ParseNumber: str:{number}, val:{parsedDouble}");
            return parsedDouble;
        }

        private void EatWhitespace()
        {
            while (char.IsWhiteSpace(PeekChar))
            {
                json.Read();

                if (json.Peek() == -1)
                    break;
            }
        }

        private enum TOKEN
        {
            NONE,

            CURLY_OPEN, // {
            CURLY_CLOSE, // }

            SQUARED_OPEN, // [
            SQUARED_CLOSE, // ]

            COLON, // :
            COMMA, // ,
            STRING, // "
            NUMBER, // 负号或数字
            TRUE, // true
            FALSE, // false
            NULL, // null
        };
    }

}
 

 

参考

用C#实现一个迷你json库,无需引入dll(可直接放到Unity中使用)_林新发的博客-CSDN博客

【Unity游戏开发】跟着马三一起魔改LitJson - 马三小伙儿 - 博客园 (cnblogs.com)

 

标签:case,return,TOKEN,private,break,json,源码,解析
From: https://www.cnblogs.com/sailJs/p/17597570.html

相关文章

  • vscode取消json文件注释下划线
    使用vscode打开一个json文件,如果有单行或多行注释,则会显示红色下划线,解决办法如下:方法1点击底部的JSON,选择JSONwithComments即可,然后红色下划线消失,底部显示如下方法2方法1重启vscode可能会失效,因此在设置中搜索files.associations,然后如下图添加项这样就不会失效了!......
  • 深度解析 Spring Boot 自动配置原理
    SpringBoot作为一个广泛使用的微服务框架,以其强大的自动配置功能而受到欢迎。这一功能使得开发者能够快速搭建和部署应用程序,无需显式配置大量组件。在这篇博客中,我们将深入探讨SpringBoot自动配置的原理,探寻其工作机制,并通过代码示例演示如何定制自动配置。1.自动配置的背后......
  • 深入解析 Spring Boot 自动配置原理
    SpringBoot作为一个广泛应用的微服务框架,以其强大的自动配置功能而受到瞩目。这一功能能够让开发人员在搭建和部署应用程序时,无需显式配置大量组件。在这篇博客中,我们将深入解析SpringBoot自动配置的原理,揭示其背后的奥秘,并通过代码示例演示如何定制自动配置。1.自动配置的核......
  • PyQt-GUI程序基本结构解析
    1.导入包与模块fromPyQt5.Qtimport*importsys创建一个应用程序对象app=QApplication(sys.argv)创建控件,设置控件window=QWidget()window.show()应用程序执行,进入到消息循环sys.exit(app.exec_())程序流程解析fromPyQt5.Qtimport*,先导入PyQt5所需......
  • 知识付费系统源码独立部署版,小鹅通源码平替
    兔知课堂是专注于知识付费领域的应用。支持图文、音频、视频、直播等内容形式,实现内容产品化,可以把多个内容打包成专栏等形式,建立体系化的内容产品,满足系统学习需求。用户可以随时随地观看自己感兴趣的内容。 后台提供页面DIY,管理员可以自主搭建个性化知识店铺页面的功能。微页......
  • 【JavaScript40】jquery发送jsonp
    jquery中也提供了jsonp请求服务器端fromflaskimportFlask,render_template,request,make_responseapp=Flask(__name__)@app.route("/")deffunc0():news="这是一个完整的html页面"returnrender_template("index.html",......
  • requests源码阅读笔记
    requests框架结构整个架构包括两部分:Session持久化参数和HTTPAdapter适配器连接请求,其余部分都是urllib3的内容。......
  • FunctionalInterface解析
    FunctionalInterface注解FunctionalInterface`是Java8新增的一个注解,使用`FunctionalInterface`注解的接口被称为`函数式接口@FunctionalInterface`注解的作用是告知编译器进行检查,可加可不加,但是如果加上了,那么接口必须为`函数式接口特点从FunctionalInterface的Doc注释可知,......
  • 来自开源社区的最大事件--- IBM收购红帽RHEL后终止提供免费的软件源和操作系统源码
    保持Linux的开放性和自由性--我们不能不这样做作者:首席企业架构师EdwardScreven和OracleLinux开发主管WimCoekaerts-2023年7月10日甲骨文加入Linux社区已有25年。这些年来,我们的目标始终如一:帮助Linux成为人人都能免费使用的最佳服务器操作系统,并为有需要的用户......
  • RT-Thead学习-GD32移植(基于RT-Thread Nano源码)
    1前言当前关于RT的移植教程有很多,纯复制大佬们的很迷糊,参考官方手册和一些经验贴,完成了基于Nano源码的移植,最简单的移植教程就是基于keil的和这一种。参考资料1.野火资料(https://doc.embedfire.com/rtos/rtthread/zh/latest/application/porting_to_stm32.html)2.微信公众号(物联网......