c++手写一个json库

json 关键原理简述

json可以是null,bool,int, double,string,array,object几个不同类型;

其中,array=vector<json>; object=map<string,json>;

所以 json 是一个多种子类的基类,代码中为 Value;

class Value
	{
	public:
		enum Type
		{
			NUL,
			INT,
			DOUBLE,
			BOOL,
			STRING,
			OBJECT,
			ARRAY,
		};

	public:
		Value(Type type)
			:type_(type)
		{

		}

		virtual std::pair<bool, int> IntValue() const
		{
			return std::make_pair(false, 0);
		}

		virtual std::pair<bool, double> DoubleValue() const
		{
			return std::make_pair(false, 0);
		}

		virtual std::pair<bool, bool> BoolValue() const
		{
			return std::make_pair(false, true);
		}

		virtual std::pair<bool, std::string> StrValue() const
		{
			return std::make_pair(false, "null string");
		}

		//virtual Object ObjectValue() const;
		
		//virtual Array ArrayValue() const ;

		virtual std::pair<bool, const Json& > at(const std::string& key) const;
		
		virtual std::pair<bool, const Json& > at(size_t i)const;

		virtual std::string GetRawStr() const=0;

		Type GetType()
		{
			return type_;
		}

	private:
		Type type_;
	};

value具有所有子类的基本函数,子类(null,bool,int, double,string,array,object)通过重写自己的函数,使得value的虚函数具有实际的意义,即返回正确的结果<true,value>。

value的子类是json类的数据成员,通过一层封装,消除不同json类型的构建的差异性,可以通过初始化列表,完成一个复杂json对象的构建。json类还提供解析字符串为json对象的功能,该功能也通过JsonParser对象外包出去。因此Json只是一层皮。

字符串解析为json的过程

字符串解析分为两种模式,一种是带有注释的json字符串解析,一种是无注释。整个解析过程是一个流水线式的解析,通过当前符号区分当前要解析的内容是什么。

Json Parse(int depth)
		{
			if (depth > max_depth) {
				return fail("exceeded maximum nesting depth");
			}

			char ch = GetNextToken();
			if (failed_)
				return Json();

			if (ch == '-' || (ch >= '0' && ch <= '9')) {
				i--;
				return ParseNumber();
			}

			if (ch == 't')
				return expect("true", true);

			if (ch == 'f')
				return expect("false", false);

			if (ch == 'n')
				return expect("null", Json());

			if (ch == '"')
				return ParseString();

			if (ch == '{') {
				Object data;
				ch = GetNextToken();
				if (ch == '}')
					return data;

				while (1) {
					if (ch != '"')
						//return fail("expected '\"' in object, got " + esc(ch));
						return fail("expected '\"' in object, got " + ch);
					std::string key = ParseString();
					if (failed_)
						return Json();

					ch = GetNextToken();
					if (ch != ':')
						//return fail("expected ':' in object, got " + esc(ch));
						return fail("expected ':' in object, got " + ch);

					data[std::move(key)] = Parse(depth + 1);
					if (failed_)
						return Json();

					ch = GetNextToken();
					if (ch == '}')
						break;
					if (ch != ',')
						//return fail("expected ',' in object, got " + esc(ch));
						return fail("expected ',' in object, got " + ch);

					ch = GetNextToken();
				}
				return data;
			}

			if (ch == '[') {
				Array data;
				ch = GetNextToken();
				if (ch == ']')
					return data;

				while (1) {
					i--;
					data.push_back(Parse(depth + 1));
					if (failed_)
						return Json();

					ch = GetNextToken();
					if (ch == ']')
						break;
					if (ch != ',')
						//return fail("expected ',' in list, got " + esc(ch));
						return fail("expected ',' in list, got " + ch);

					ch = GetNextToken();
					(void)ch;
				}
				return data;
			}

			//return fail("expected value, got " + esc(ch));
			return fail("expected value, got " + ch);
		}

主要部分object和array类型的解析都是递归的过程。

关键函数解析

解析过程中出现错误怎么处理?

        Json fail(std::string&& msg) {
			return fail(move(msg), Json());
		}

		template <typename T>
		T fail(std::string&& msg, const T err_ret) {
			if (!failed_)
				err_ = std::move(msg);
			failed_ = true;
			return err_ret;
		}

解析过程中出现错误往往要返回一个值,用户通过返回值判断该解析过程或者子解析过程是否出现错误。这是json11处理方式,通过模板可以返回不同的类型满足各部分解析返回值需求,并且生成错误信息。

解析特定类型的函数抽象

Json expect(const std::string& expected, Json res) {
			if (i == 0)
			{
				return fail("expect wrong i(position of str_)", Json());
			}
			i--;
			if (str_.compare(i, expected.length(), expected) == 0) {
				i += expected.length();
				return res;
			}
			else {
				return fail("parse error: expected " + expected + ", got " + str_.substr(i, expected.length()));
			}
		}

在对bool和null类型解析是一个类似的过程,采用expect()进行抽象,一个string对应一个json对象。

json对象字符串的输出

不同json类型有不同的字符串输出方式,并且和解析一样存在递归调用如果都放到自己的成员函数下,递归调用就成问题。因此将字符串输出代理给RawStr类。RawStr具有一系列static的GetRawStr()函数,彼此间相互调用。

另一种还是将字符串输出放到各类型内部,递归调用时,通过构建临时Json对象,递归调用获取json字符串的函数。

参考

大部分源码来源于json11,进行了自己的阅读理解,用简单的方式组合在一起,并去除了编码相关的模块,不考虑编码的问题。

源码

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值