今天小编给大家分享一下怎么用C++编写一个Json解析器的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
之前用RapidJson来做json的解析,但是,RapidJson还是有麻烦的地方,虽然速度非常快,但是由于用了非常多的优化技巧,反而无法做到我想要的那种简便的访问方式。
比如,有这么一个字符串:
"{ "a":1000,"b":30000,"c":[123,456,789,5555, 1.0e2, true, false, null, "test", "big big world"]}"
我在C++里面需要非常简单的使用它,例如这样:
static char text[] = "{ "a":1000,"b":30000,"c":[123,456,789,5555, 1.0e2, true, false, null, "test", "big big world"]}";
atom::CJson root = text;
root["a"] = 123;
root["c"] = true;
root["b"] = "b is the biggest";
atom::CJson test = "{"new key": 1037, 'test-key':1234e-5, 'array':[1,2,3,1,1,0] }";
root["e"] = test;
test["array"][0] = 1000;
atom::a_string value = root.Stringity();
printf( "%s
", 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文件
#ifndef TAGJSONTOKEN_H
#define TAGJSONTOKEN_H
//Begin section for file tagJsonToken.h
//TODO: Add definitions that you want preserved
//End section for file tagJsonToken.h
#include "../stl/a_string.h"
#include "../stl/allocator.h"
#include "../tool/CVariablePtr.h"
namespace atom
{
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
struct tagJsonToken
{
//Begin section for atom::tagJsonToken
//TODO: Add attributes that you want preserved
//End section for atom::tagJsonToken
public:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
//typedef CVariablePtr<tagJsonToken> Ptr ;
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
typedef vector<tagJsonToken, atom_allocator<tagJsonToken> > Array ;
public:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
U32 token;
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
size_t start;
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
size_t close;
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
tagJsonToken();
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
tagJsonToken(const tagJsonToken & value);
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
tagJsonToken(U32 token);
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
tagJsonToken(U32 token, size_t start, size_t close);
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
~tagJsonToken();
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
tagJsonToken & operator=(const tagJsonToken & value);
}; //end struct tagJsonToken
} //end namespace nova
#endif
#include "tagJsonToken.h"
//Begin section for file tagJsonToken.cpp
//TODO: Add definitions that you want preserved
//End section for file tagJsonToken.cpp
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
atom::tagJsonToken::tagJsonToken() :
token(0),start(0),close(0)
{
//TODO Auto-generated method stub
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
atom::tagJsonToken::tagJsonToken(const tagJsonToken & in) :
token(in.token),start(in.start),close(in.close)
{
//TODO Auto-generated method stub
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
atom::tagJsonToken::tagJsonToken(U32 t) :
token(t),start(0),close(0)
{
//TODO Auto-generated method stub
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
atom::tagJsonToken::tagJsonToken(U32 t, size_t s, size_t c) :
token(t),start(s),close(c)
{
//TODO Auto-generated method stub
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
atom::tagJsonToken::~tagJsonToken()
{
//TODO Auto-generated method stub
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
atom::tagJsonToken & atom::tagJsonToken::operator=(const tagJsonToken & in)
{
//TODO Auto-generated method stub
token = in.token;
start = in.start;
close = in.close;
return( * this );
}
json节点的头文件和cpp文件
#ifndef TAGJSONKEYVALUE_H
#define TAGJSONKEYVALUE_H
//Begin section for file tagJsonKeyValue.h
//TODO: Add definitions that you want preserved
//End section for file tagJsonKeyValue.h
#include "../stl/a_string.h"
#include "../stl/stl_extend.h"
#include "../variant/CVariant.h"
#include "../tool/CVariablePtr.h"
namespace atom
{
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
struct tagJsonKeyValue
{
//Begin section for atom::tagJsonKeyValue
//TODO: Add attributes that you want preserved
//End section for atom::tagJsonKeyValue
public:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
typedef CVariablePtr<tagJsonKeyValue> Ptr ;
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
typedef vector<pair<size_t, tagJsonKeyValue::Ptr>, atom_allocator<pair<size_t, tagJsonKeyValue::Ptr> > > Array ;
public:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
a_string index;
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
CVariant value;
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
Array group;
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
//Map query;
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
tagJsonKeyValue();
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
tagJsonKeyValue(const char * value);
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
tagJsonKeyValue(const CVariant & data);
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
tagJsonKeyValue(const char * value, const CVariant & data);
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
tagJsonKeyValue(const tagJsonKeyValue & value);
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
~tagJsonKeyValue();
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
tagJsonKeyValue & operator=(const tagJsonKeyValue & value);
}; //end struct tagJsonKeyValue
} //end namespace atom
template<class Archive>
inline void Serialize(Archive & archive, atom::tagJsonKeyValue & value, bool isSave)
{
UNREFERENCED_PARAMETER( isSave );
archive.Bind( value.index );
archive.Bind( value.value );
archive.Bind( value.group );
}
#endif
#include "tagJsonKeyValue.h"
//Begin section for file tagJsonKeyValue.cpp
//TODO: Add definitions that you want preserved
//End section for file tagJsonKeyValue.cpp
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
atom::tagJsonKeyValue::tagJsonKeyValue()
{
//TODO Auto-generated method stub
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
atom::tagJsonKeyValue::tagJsonKeyValue(const char * in):
index(in ? in : "")
{
//TODO Auto-generated method stub
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
atom::tagJsonKeyValue::tagJsonKeyValue(const CVariant & in) :
value(in)
{
//TODO Auto-generated method stub
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
atom::tagJsonKeyValue::tagJsonKeyValue(const char * in_1, const CVariant & in_2) :
index(in_1 ? in_1 : ""),value(in_2)
{
//TODO Auto-generated method stub
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
atom::tagJsonKeyValue::tagJsonKeyValue(const tagJsonKeyValue & in) :
index(in.index),value(in.value),group(in.group)
{
//TODO Auto-generated method stub
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
atom::tagJsonKeyValue::~tagJsonKeyValue()
{
//TODO Auto-generated method stub
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
atom::tagJsonKeyValue & atom::tagJsonKeyValue::operator=(const tagJsonKeyValue & in)
{
//TODO Auto-generated method stub
index = in.index;
value = in.value;
group = in.group;
return( * this );
}
接下来是 Tokenizer 的实现
#include "CJsonTokenizer.h"
#include "../../enumeration/JSON_TOKEN.h"
//Begin section for file CJsonTokenizer.cpp
//TODO: Add definitions that you want preserved
//End section for file CJsonTokenizer.cpp
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
atom::CJsonTokenizer::CJsonTokenizer()
{
//TODO Auto-generated method stub
tokens.reserve( 1024 );
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
atom::CJsonTokenizer::~CJsonTokenizer()
{
//TODO Auto-generated method stub
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
bool atom::CJsonTokenizer::Start(const char * json)
{
//TODO Auto-generated method stub
if( json == NULL ) {
return false;
}
size_t offset = 0;
size_t length = strlen( json );
buffer.Alloc( length );
if( buffer ) {
buffer.Store( json, length );
}
bool result = true;
for( ;; )
{
// skip any reserved or space characters.
for( ; IsSpace(json, offset, length); ++ offset );
// offset check
if( offset >= length )
{
tokens.push_back( tagJsonToken() );
tokens.back().token = JT_END;
break;
}
char c = json[offset];
// create token
if( IsNull(json, offset, length) )
{
offset += 4;
tokens.push_back( tagJsonToken(JT_NULL) );
}
else
if( c == ',' )
{
offset += 1;
tokens.push_back( tagJsonToken(JT_COMMA) );
}
else
if( c == ':' )
{
offset += 1;
tokens.push_back( tagJsonToken(JT_COLON) );
}
else
if( c == '{' )
{
offset += 1;
tokens.push_back( tagJsonToken(JT_OBJECT_BEGIN) );
}
else
if( c == '[' )
{
offset += 1;
tokens.push_back( tagJsonToken(JT_ARRAY_BEGIN) );
}
else
if( c == ']' )
{
offset += 1;
tokens.push_back( tagJsonToken(JT_ARRAY_CLOSE) );
}
else
if( c == '}' )
{
offset += 1;
tokens.push_back( tagJsonToken(JT_OBJECT_CLOSE) );
}
else
if( IsTrue(json, offset, length) )
{
offset += 4;
tokens.push_back( tagJsonToken(JT_BOOL, 1, 0) );
}
else
if( IsFalse(json, offset, length) )
{
offset += 5;
tokens.push_back( tagJsonToken(JT_BOOL) );
}
else
if( c == ''' || c == '"' )
{
// read string will modify the offset;
size_t start(0), close(0);
ReadString( json, offset, length, start, close );
if( start == 0 || close == 0 || close <= start )
{
char msg[32];
sprintf( msg, "%zu", offset );
errmsg = "Failed read string from offset ";
errmsg = errmsg + msg;
tokens.clear();
result = false;
break;
}
tokens.push_back( tagJsonToken(JT_STRING, start, close) );
}
else
if( IsNumber(json, offset, length) )
{
size_t start(0), close(0);
ReadNumber( json, offset, length, start, close );
// read number will modify the offset;
if( start == 0 || close == 0 || close <= start )
{
char msg[32];
sprintf( msg, "%zu", offset );
errmsg = "Failed read number from offset ";
errmsg = errmsg + msg;
tokens.clear();
result = false;
break;
}
tokens.push_back( tagJsonToken(JT_NUMBER, start, close) );
}
else
{
char msg[32];
sprintf( msg, "%zu", offset );
errmsg = "Invalid char at offset ";
errmsg = errmsg + msg;
tokens.clear();
result = false;
break;
}
}
return result;
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
bool atom::CJsonTokenizer::IsNull(const char * json, size_t & offset, size_t length)
{
//TODO Auto-generated method stub
bool result = false;
if( json )
{
// length must enough.
if( (length - offset) + 1 >= 4 )
{
const char * site = json + offset;
if( *site == 'n' || *site == 'N' )
{
++ site;
if( *site == 'u' || *site == 'U' )
{
++ site;
if( *site == 'l' || *site == 'L' )
{
++ site;
if( *site == 'l' || *site == 'L' )
{
result = true;
}
}
}
}
}
}
return result;
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
bool atom::CJsonTokenizer::IsTrue(const char * json, size_t & offset, size_t length)
{
//TODO Auto-generated method stub
bool result = false;
if( json )
{
// length must enough.
if( (length - offset) + 1 >= 4 )
{
const char * site = json + offset;
if( *site == 't' || *site == 'T' )
{
++ site;
if( *site == 'r' || *site == 'R' )
{
++ site;
if( *site == 'u' || *site == 'U' )
{
++ site;
if( *site == 'e' || *site == 'E' )
{
result = true;
}
}
}
}
}
}
return result;
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
bool atom::CJsonTokenizer::IsFalse(const char * json, size_t & offset, size_t length)
{
//TODO Auto-generated method stub
bool result = false;
if( json )
{
// length must enough.
if( (length - offset) + 1 >= 5 )
{
const char * site = json + offset;
if( *site == 'f' || *site == 'F' )
{
++ site;
if( *site == 'a' || *site == 'A' )
{
++ site;
if( *site == 'l' || *site == 'L' )
{
++ site;
if( *site == 's' || *site == 'S' )
{
++ site;
if( *site == 'e' || *site == 'E' )
{
result = true;
}
}
}
}
}
}
}
return result;
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
bool atom::CJsonTokenizer::IsSpace(const char * json, size_t & offset, size_t length)
{
//TODO Auto-generated method stub
if( !json ) {
return false;
}
bool result = false;
if( offset < length )
{
if( json[offset] <= 0x20 )
{
result = true;
}
}
return result;
}
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
bool atom::CJsonTokenizer::IsNumber(const char * json, size_t & offset, size_t length)
{
//TODO Auto-generated method stub
if( !json ) {
&
版权声明:除特别声明外,本站所有文章皆是本站原创,转载请以超链接形式注明出处!