怎么用C++编写一个Json解析器

前端开发   发布日期:2023年08月17日   浏览次数:519

今天小编给大家分享一下怎么用C++编写一个Json解析器的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

之前用RapidJson来做json的解析,但是,RapidJson还是有麻烦的地方,虽然速度非常快,但是由于用了非常多的优化技巧,反而无法做到我想要的那种简便的访问方式。

比如,有这么一个字符串:

  1. "{ "a":1000,"b":30000,"c":[123,456,789,5555, 1.0e2, true, false, null, "test", "big big world"]}"

我在C++里面需要非常简单的使用它,例如这样:

  1. static char text[] = "{ "a":1000,"b":30000,"c":[123,456,789,5555, 1.0e2, true, false, null, "test", "big big world"]}";
  2. atom::CJson root = text;
  3. root["a"] = 123;
  4. root["c"] = true;
  5. root["b"] = "b is the biggest";
  6. atom::CJson test = "{"new key": 1037, 'test-key':1234e-5, 'array':[1,2,3,1,1,0] }";
  7. root["e"] = test;
  8. test["array"][0] = 1000;
  9. atom::a_string value = root.Stringity();
  10. printf( "%s
  11. ", value.c_str() );

而输出结果如下:

{"a":123, "b":"b is the biggest", "c":1, "e":{"new key":1037, "test-key":0.012340, "array":[1000, 2, 3, 1, 1, 0, ], }, }

找了几个Json库,似乎都没有我想要的那种效果。快的访问很麻烦,访问方便点的速度又上不去。后来还是决定自己写一个。

自己写出来后,测试了一下,在不开优化的情况下,时间开销大概是RapidJson的8倍,如果开编译器优化,则时间开销是RapidJson的4倍左右。其实还是有可以再优化的地方,但再优化就必须要损失易用性为代价。想了一下,还是放弃了,这个解析速度和访问的方便程度我已经很满意了。

而且我自己写的Json还能支持序列化到流数据,如果采用这个方式,恢复的速度和RapidJson的解析差不多。

tokenizer数据结构的头文件和cpp文件

  1. #ifndef TAGJSONTOKEN_H
  2. #define TAGJSONTOKEN_H
  3. //Begin section for file tagJsonToken.h
  4. //TODO: Add definitions that you want preserved
  5. //End section for file tagJsonToken.h
  6. #include "../stl/a_string.h"
  7. #include "../stl/allocator.h"
  8. #include "../tool/CVariablePtr.h"
  9. namespace atom
  10. {
  11. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  12. struct tagJsonToken
  13. {
  14. //Begin section for atom::tagJsonToken
  15. //TODO: Add attributes that you want preserved
  16. //End section for atom::tagJsonToken
  17. public:
  18. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  19. //typedef CVariablePtr<tagJsonToken> Ptr ;
  20. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  21. typedef vector<tagJsonToken, atom_allocator<tagJsonToken> > Array ;
  22. public:
  23. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  24. U32 token;
  25. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  26. size_t start;
  27. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  28. size_t close;
  29. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  30. tagJsonToken();
  31. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  32. tagJsonToken(const tagJsonToken & value);
  33. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  34. tagJsonToken(U32 token);
  35. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  36. tagJsonToken(U32 token, size_t start, size_t close);
  37. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  38. ~tagJsonToken();
  39. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  40. tagJsonToken & operator=(const tagJsonToken & value);
  41. }; //end struct tagJsonToken
  42. } //end namespace nova
  43. #endif
  1. #include "tagJsonToken.h"
  2. //Begin section for file tagJsonToken.cpp
  3. //TODO: Add definitions that you want preserved
  4. //End section for file tagJsonToken.cpp
  5. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  6. atom::tagJsonToken::tagJsonToken() :
  7. token(0),start(0),close(0)
  8. {
  9. //TODO Auto-generated method stub
  10. }
  11. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  12. atom::tagJsonToken::tagJsonToken(const tagJsonToken & in) :
  13. token(in.token),start(in.start),close(in.close)
  14. {
  15. //TODO Auto-generated method stub
  16. }
  17. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  18. atom::tagJsonToken::tagJsonToken(U32 t) :
  19. token(t),start(0),close(0)
  20. {
  21. //TODO Auto-generated method stub
  22. }
  23. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  24. atom::tagJsonToken::tagJsonToken(U32 t, size_t s, size_t c) :
  25. token(t),start(s),close(c)
  26. {
  27. //TODO Auto-generated method stub
  28. }
  29. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  30. atom::tagJsonToken::~tagJsonToken()
  31. {
  32. //TODO Auto-generated method stub
  33. }
  34. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  35. atom::tagJsonToken & atom::tagJsonToken::operator=(const tagJsonToken & in)
  36. {
  37. //TODO Auto-generated method stub
  38. token = in.token;
  39. start = in.start;
  40. close = in.close;
  41. return( * this );
  42. }

json节点的头文件和cpp文件

  1. #ifndef TAGJSONKEYVALUE_H
  2. #define TAGJSONKEYVALUE_H
  3. //Begin section for file tagJsonKeyValue.h
  4. //TODO: Add definitions that you want preserved
  5. //End section for file tagJsonKeyValue.h
  6. #include "../stl/a_string.h"
  7. #include "../stl/stl_extend.h"
  8. #include "../variant/CVariant.h"
  9. #include "../tool/CVariablePtr.h"
  10. namespace atom
  11. {
  12. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  13. struct tagJsonKeyValue
  14. {
  15. //Begin section for atom::tagJsonKeyValue
  16. //TODO: Add attributes that you want preserved
  17. //End section for atom::tagJsonKeyValue
  18. public:
  19. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  20. typedef CVariablePtr<tagJsonKeyValue> Ptr ;
  21. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  22. typedef vector<pair<size_t, tagJsonKeyValue::Ptr>, atom_allocator<pair<size_t, tagJsonKeyValue::Ptr> > > Array ;
  23. public:
  24. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  25. a_string index;
  26. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  27. CVariant value;
  28. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  29. Array group;
  30. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  31. //Map query;
  32. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  33. tagJsonKeyValue();
  34. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  35. tagJsonKeyValue(const char * value);
  36. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  37. tagJsonKeyValue(const CVariant & data);
  38. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  39. tagJsonKeyValue(const char * value, const CVariant & data);
  40. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  41. tagJsonKeyValue(const tagJsonKeyValue & value);
  42. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  43. ~tagJsonKeyValue();
  44. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  45. tagJsonKeyValue & operator=(const tagJsonKeyValue & value);
  46. }; //end struct tagJsonKeyValue
  47. } //end namespace atom
  48. template<class Archive>
  49. inline void Serialize(Archive & archive, atom::tagJsonKeyValue & value, bool isSave)
  50. {
  51. UNREFERENCED_PARAMETER( isSave );
  52. archive.Bind( value.index );
  53. archive.Bind( value.value );
  54. archive.Bind( value.group );
  55. }
  56. #endif
  1. #include "tagJsonKeyValue.h"
  2. //Begin section for file tagJsonKeyValue.cpp
  3. //TODO: Add definitions that you want preserved
  4. //End section for file tagJsonKeyValue.cpp
  5. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  6. atom::tagJsonKeyValue::tagJsonKeyValue()
  7. {
  8. //TODO Auto-generated method stub
  9. }
  10. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  11. atom::tagJsonKeyValue::tagJsonKeyValue(const char * in):
  12. index(in ? in : "")
  13. {
  14. //TODO Auto-generated method stub
  15. }
  16. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  17. atom::tagJsonKeyValue::tagJsonKeyValue(const CVariant & in) :
  18. value(in)
  19. {
  20. //TODO Auto-generated method stub
  21. }
  22. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  23. atom::tagJsonKeyValue::tagJsonKeyValue(const char * in_1, const CVariant & in_2) :
  24. index(in_1 ? in_1 : ""),value(in_2)
  25. {
  26. //TODO Auto-generated method stub
  27. }
  28. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  29. atom::tagJsonKeyValue::tagJsonKeyValue(const tagJsonKeyValue & in) :
  30. index(in.index),value(in.value),group(in.group)
  31. {
  32. //TODO Auto-generated method stub
  33. }
  34. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  35. atom::tagJsonKeyValue::~tagJsonKeyValue()
  36. {
  37. //TODO Auto-generated method stub
  38. }
  39. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  40. atom::tagJsonKeyValue & atom::tagJsonKeyValue::operator=(const tagJsonKeyValue & in)
  41. {
  42. //TODO Auto-generated method stub
  43. index = in.index;
  44. value = in.value;
  45. group = in.group;
  46. return( * this );
  47. }

接下来是 Tokenizer 的实现

  1. #include "CJsonTokenizer.h"
  2. #include "../../enumeration/JSON_TOKEN.h"
  3. //Begin section for file CJsonTokenizer.cpp
  4. //TODO: Add definitions that you want preserved
  5. //End section for file CJsonTokenizer.cpp
  6. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  7. atom::CJsonTokenizer::CJsonTokenizer()
  8. {
  9. //TODO Auto-generated method stub
  10. tokens.reserve( 1024 );
  11. }
  12. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  13. atom::CJsonTokenizer::~CJsonTokenizer()
  14. {
  15. //TODO Auto-generated method stub
  16. }
  17. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  18. bool atom::CJsonTokenizer::Start(const char * json)
  19. {
  20. //TODO Auto-generated method stub
  21. if( json == NULL ) {
  22. return false;
  23. }
  24. size_t offset = 0;
  25. size_t length = strlen( json );
  26. buffer.Alloc( length );
  27. if( buffer ) {
  28. buffer.Store( json, length );
  29. }
  30. bool result = true;
  31. for( ;; )
  32. {
  33. // skip any reserved or space characters.
  34. for( ; IsSpace(json, offset, length); ++ offset );
  35. // offset check
  36. if( offset >= length )
  37. {
  38. tokens.push_back( tagJsonToken() );
  39. tokens.back().token = JT_END;
  40. break;
  41. }
  42. char c = json[offset];
  43. // create token
  44. if( IsNull(json, offset, length) )
  45. {
  46. offset += 4;
  47. tokens.push_back( tagJsonToken(JT_NULL) );
  48. }
  49. else
  50. if( c == ',' )
  51. {
  52. offset += 1;
  53. tokens.push_back( tagJsonToken(JT_COMMA) );
  54. }
  55. else
  56. if( c == ':' )
  57. {
  58. offset += 1;
  59. tokens.push_back( tagJsonToken(JT_COLON) );
  60. }
  61. else
  62. if( c == '{' )
  63. {
  64. offset += 1;
  65. tokens.push_back( tagJsonToken(JT_OBJECT_BEGIN) );
  66. }
  67. else
  68. if( c == '[' )
  69. {
  70. offset += 1;
  71. tokens.push_back( tagJsonToken(JT_ARRAY_BEGIN) );
  72. }
  73. else
  74. if( c == ']' )
  75. {
  76. offset += 1;
  77. tokens.push_back( tagJsonToken(JT_ARRAY_CLOSE) );
  78. }
  79. else
  80. if( c == '}' )
  81. {
  82. offset += 1;
  83. tokens.push_back( tagJsonToken(JT_OBJECT_CLOSE) );
  84. }
  85. else
  86. if( IsTrue(json, offset, length) )
  87. {
  88. offset += 4;
  89. tokens.push_back( tagJsonToken(JT_BOOL, 1, 0) );
  90. }
  91. else
  92. if( IsFalse(json, offset, length) )
  93. {
  94. offset += 5;
  95. tokens.push_back( tagJsonToken(JT_BOOL) );
  96. }
  97. else
  98. if( c == ''' || c == '"' )
  99. {
  100. // read string will modify the offset;
  101. size_t start(0), close(0);
  102. ReadString( json, offset, length, start, close );
  103. if( start == 0 || close == 0 || close <= start )
  104. {
  105. char msg[32];
  106. sprintf( msg, "%zu", offset );
  107. errmsg = "Failed read string from offset ";
  108. errmsg = errmsg + msg;
  109. tokens.clear();
  110. result = false;
  111. break;
  112. }
  113. tokens.push_back( tagJsonToken(JT_STRING, start, close) );
  114. }
  115. else
  116. if( IsNumber(json, offset, length) )
  117. {
  118. size_t start(0), close(0);
  119. ReadNumber( json, offset, length, start, close );
  120. // read number will modify the offset;
  121. if( start == 0 || close == 0 || close <= start )
  122. {
  123. char msg[32];
  124. sprintf( msg, "%zu", offset );
  125. errmsg = "Failed read number from offset ";
  126. errmsg = errmsg + msg;
  127. tokens.clear();
  128. result = false;
  129. break;
  130. }
  131. tokens.push_back( tagJsonToken(JT_NUMBER, start, close) );
  132. }
  133. else
  134. {
  135. char msg[32];
  136. sprintf( msg, "%zu", offset );
  137. errmsg = "Invalid char at offset ";
  138. errmsg = errmsg + msg;
  139. tokens.clear();
  140. result = false;
  141. break;
  142. }
  143. }
  144. return result;
  145. }
  146. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  147. bool atom::CJsonTokenizer::IsNull(const char * json, size_t & offset, size_t length)
  148. {
  149. //TODO Auto-generated method stub
  150. bool result = false;
  151. if( json )
  152. {
  153. // length must enough.
  154. if( (length - offset) + 1 >= 4 )
  155. {
  156. const char * site = json + offset;
  157. if( *site == 'n' || *site == 'N' )
  158. {
  159. ++ site;
  160. if( *site == 'u' || *site == 'U' )
  161. {
  162. ++ site;
  163. if( *site == 'l' || *site == 'L' )
  164. {
  165. ++ site;
  166. if( *site == 'l' || *site == 'L' )
  167. {
  168. result = true;
  169. }
  170. }
  171. }
  172. }
  173. }
  174. }
  175. return result;
  176. }
  177. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  178. bool atom::CJsonTokenizer::IsTrue(const char * json, size_t & offset, size_t length)
  179. {
  180. //TODO Auto-generated method stub
  181. bool result = false;
  182. if( json )
  183. {
  184. // length must enough.
  185. if( (length - offset) + 1 >= 4 )
  186. {
  187. const char * site = json + offset;
  188. if( *site == 't' || *site == 'T' )
  189. {
  190. ++ site;
  191. if( *site == 'r' || *site == 'R' )
  192. {
  193. ++ site;
  194. if( *site == 'u' || *site == 'U' )
  195. {
  196. ++ site;
  197. if( *site == 'e' || *site == 'E' )
  198. {
  199. result = true;
  200. }
  201. }
  202. }
  203. }
  204. }
  205. }
  206. return result;
  207. }
  208. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  209. bool atom::CJsonTokenizer::IsFalse(const char * json, size_t & offset, size_t length)
  210. {
  211. //TODO Auto-generated method stub
  212. bool result = false;
  213. if( json )
  214. {
  215. // length must enough.
  216. if( (length - offset) + 1 >= 5 )
  217. {
  218. const char * site = json + offset;
  219. if( *site == 'f' || *site == 'F' )
  220. {
  221. ++ site;
  222. if( *site == 'a' || *site == 'A' )
  223. {
  224. ++ site;
  225. if( *site == 'l' || *site == 'L' )
  226. {
  227. ++ site;
  228. if( *site == 's' || *site == 'S' )
  229. {
  230. ++ site;
  231. if( *site == 'e' || *site == 'E' )
  232. {
  233. result = true;
  234. }
  235. }
  236. }
  237. }
  238. }
  239. }
  240. }
  241. return result;
  242. }
  243. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  244. bool atom::CJsonTokenizer::IsSpace(const char * json, size_t & offset, size_t length)
  245. {
  246. //TODO Auto-generated method stub
  247. if( !json ) {
  248. return false;
  249. }
  250. bool result = false;
  251. if( offset < length )
  252. {
  253. if( json[offset] <= 0x20 )
  254. {
  255. result = true;
  256. }
  257. }
  258. return result;
  259. }
  260. //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
  261. bool atom::CJsonTokenizer::IsNumber(const char * json, size_t & offset, size_t length)
  262. {
  263. //TODO Auto-generated method stub
  264. if( !json ) {
  265. &amp

以上就是怎么用C++编写一个Json解析器的详细内容,更多关于怎么用C++编写一个Json解析器的资料请关注九品源码其它相关文章!