«

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

时间:2024-8-5 09:34     作者:韩俊     分类: Javascript


今天小编给大家分享一下怎么用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 ) {
&

标签: javascript

热门推荐