irpas技术客

c++手写一个json库_三十而学_c++ json库

网络 1371

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,进行了自己的阅读理解,用简单的方式组合在一起,并去除了编码相关的模块,不考虑编码的问题。

源码


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #C #json库 #JSON #test0 #Object #quotkey1quot