json 是一种基于文本的轻量级的数据格式,类似于 xml,
它简单灵活而且被广泛的语言支持,是一种理想的数据交换格式。
http://json.org/ 这里是一个 json 格式说明 以及相关语言解析库的列表。
可以看到对于大多数语言已经有了可以选择的 lib
这个文章接下来将会进行一次重复造轮子的尝试,实现一个c++ 下解析 json 的什么东西。
----------分割线--------------
首先来分析下 json 格式。
json 数据时基于文本的,也就是字符串,以 '\0' 结尾。
它的通用单位(这是我的叫法,原文为value)可以是以下之一:
首先看string
类似 c++ 的字符串,由双引号括起的 UNICODE 字符,可以用 '\' 转义。
>数字 Number
和 c++ 的定义一致,除了没有8进制和16进制。
对象 Object
我觉得它更类似于 c ++ 的 pair,由“键” 和 “值” 构成的 “对”
这里的“值”又可以是最开始图中的7种之一。{"action":1}
array 数组
数组是若干个 value 的有序集合。[1,2,3,4,5,6]
true false相当于 c++ 中的 bool 类型了。
null空类型。
----------分割线--------------
下面是解析json的代码 未完成。
----------分割线--------------
#include <string>
#include <sstream>
#include <vector>
#include <map>
#include <stdexcept>
#include <fstream>
using namespace std;
enum JsonTypeEnum
{
JsonTypeString = 0,
JsonTypeNumber,
JsonTypeBool,
JsonTypeNull,
JsonTypeObject,
JsonTypeArray
};
class JsonString;
class JsonNumber;
class JsonBool;
class JsonNull;
class JsonObject;
class JsonArray;
class JsonBase
{
public:
virtual ~JsonBase(){};
virtual string Serialize() = 0;
virtual int Type() = 0;
JsonBase & operator[](string key);
JsonBase & operator[](unsigned int index);
};
class JsonString : public JsonBase
{
public:
~JsonString()
{
}
string Serialize()
{
return "\"" + value + "\"";
}
int Type()
{
return JsonTypeString;
}
//
string value;
};
class JsonNumber : public JsonBase
{
public:
~JsonNumber()
{
}
string Serialize()
{
stringstream ss;
ss.precision(10);
ss << value;
return ss.str();
}
int Type()
{
return JsonTypeNumber;
}
//
double value;
};
class JsonBool : public JsonBase
{
public:
~JsonBool()
{
}
string Serialize()
{
return value?"true":"false";
}
int Type()
{
return JsonTypeBool;
}
//
bool value;
};
class JsonNull : public JsonBase
{
public:
~JsonNull()
{
}
string Serialize()
{
return "null";
}
int Type()
{
return JsonTypeNull;
}
//
};
class JsonObject : public JsonBase
{
public:
~JsonObject()
{
for( map<string, JsonBase *>::iterator it = value.begin();
it != value.end();
it++ )
{
delete (*it).second;
}
value.clear();
}
string Serialize()
{
string s("");
s += "{";
for( map<string, JsonBase *>::iterator it = value.begin();
it != value.end();
it++ )
{
s += "\"";
s += (*it).first;
s += "\":";
s += (*it).second->Serialize();
s += ",";
}
s = s.substr(0,s.length()-1);
s += "}";
return s;
}
int Type()
{
return JsonTypeObject;
}
//
map<string, JsonBase *> value;
};
class JsonArray : public JsonBase
{
public:
~JsonArray()
{
for( vector<JsonBase *>::iterator it = value.begin();
it != value.end();
it++ )
{
delete (*it);
}
value.clear();
}
string Serialize()
{
string s("");
s += "[";
for( vector<JsonBase *>::iterator it = value.begin();
it != value.end();
it++ )
{
s += (*it)->Serialize();
s += ",";
}
s = s.substr(0,s.length()-1);
s += "]";
return s;
}
int Type()
{
return JsonTypeArray;
}
vector<JsonBase *> value;
};
inline bool IsSpaceChar(char c)
{
if(c==' '|| c=='\t'|| c=='\r'|| c=='\n')return true;
return false;
}
JsonBase * JsonParse(const char * j)
{
string t; // token
const char * p = j; // position
const char * q = NULL;
while(*p)
{
if(IsSpaceChar(*p))while(IsSpaceChar(*p))p++;
// string
if(*p=='"')
{
q = p+1;
while(*q!='\"')
if(!*q++)
return NULL;
t = string(p+1,q);
q ++;
if(IsSpaceChar(*q))while(IsSpaceChar(*q))q++;
if(*q)
return NULL;
JsonString * js = new JsonString;
js->value = t;
return js;
}
// number dec
if(*p>='0' && *p<='9')
{
bool dot = false;
q = p+1;
while(*q>='0' && *q<='9' || *q=='.' && (dot=!dot))q++;
t = string(p,q);
//q ++;
if(IsSpaceChar(*q))while(IsSpaceChar(*q))q++;
if(*q)
return NULL;
stringstream ss;
ss << t;
JsonNumber * jn = new JsonNumber;
ss >> jn->value;
return jn;
}
// bool true
if(*p == 't'&& *(p+1) == 'r'&& *(p+2)=='u'&& *(p+3)=='e')
{
q = p+4;
if(IsSpaceChar(*q))while(IsSpaceChar(*q))q++;
if(*q)
return NULL;
JsonBool * jb = new JsonBool;
jb->value = true;
return jb;
}
// bool false
if(*p == 'f'&& *(p+1) == 'a'&& *(p+2)=='l'&& *(p+3)=='s'&& *(p+4)=='e')
{
q = p+5;
if(IsSpaceChar(*q))while(IsSpaceChar(*q))q++;
if(*q)
return NULL;
JsonBool * jb = new JsonBool;
jb->value = false;
return jb;
}
// null
if(*p == 'n'&& *(p+1) == 'u'&& *(p+2)=='l'&& *(p+3)=='l')
{
q = p+4;
if(IsSpaceChar(*q))while(IsSpaceChar(*q))q++;
if(*q)
return NULL;
JsonNull * jb = new JsonNull;
return jb;
}
// object
if(*p == '{')
{
p++;
JsonObject * jo = new JsonObject();
while(*p)
{
if(IsSpaceChar(*p))while(IsSpaceChar(*p))p++; // skip space
q = p;
bool qt = false;
if(*q == '\"') // key with qt
{
bool shift = false;
while(*q++)
{
if(*q == '\"' && !shift) // 2nd qt without shift
{
t = string(p+1, q-1);
q ++; // skip the qt
break;
}
}
}
else // without qt, so take a word
{
while(*q)
{
if(!(*q>='0' && *q<='9' ||
*q>='a' && *q<='z' ||
*q>='A' && *q<='Z' ||
*q == '_' ))
{
if(p == q)
return NULL;
t = string(p, q);
break;
}
q ++;
}
}
// now key in token
if(IsSpaceChar(*q))while(IsSpaceChar(*q))q++;
if(*q!=':')
return NULL;
q ++;
p = q;
if(IsSpaceChar(*p))while(IsSpaceChar(*p))p++;
q = p;
qt = false;
int st = 0; // stack
while(*q)
{
if(*q == '\"')qt = !qt;
if(*q == '{' && !qt)st ++; // stack ++
if(*q == '}' && !qt)
{
if(st)st--; // stack --
else break; // stack empty
}
if(*q == ',' && !qt)
{
if(!st)break;
}
q++;
}
if(*q == '}')
{
string v(p, q);
JsonBase * jb = JsonParse(v.c_str());
if(!jb)
return NULL;
jo->value[t] = jb;
return jo;
}
else if(*q == ',')
{
string v(p, q);
JsonBase * jb = JsonParse(v.c_str());
if(!jb)
return NULL;
jo->value[t] = jb;
p = q+1;
}
else
{
return NULL;
}
} // while
}
if(*p == '[')
{
p ++;
JsonArray * ja = new JsonArray;
q = p;
while(*q)
{
int st1 = 0; // stack {}
int st2 = 0; // stack []
bool qt = false;
bool shift = false;
if(IsSpaceChar(*q))while(IsSpaceChar(*q))q++;
while(*q)
{
if(*q == '\"')qt = !qt;
if(*q == '{' && !qt)st1++;
if(*q == '}' && !qt)
{
if(st1)st1--;
else
{
delete ja;
return NULL;
}
}
if(*q == '[' && !qt)st2++;
if(*q == ']' && !qt)
{
if(st2)st2--;
if(!st2)
{
string v(p, q); // j = JsonParse("[1,2,3,4,5,false,\"7\"]");
JsonBase * jb = JsonParse(v.c_str());
if(!jb)
{
delete ja;
return NULL;
}
ja->value.push_back(jb);
return ja;
}
}
if(*q == ',' && !qt && !st1 && !st2)
{
string v(p, q);
JsonBase * jb = JsonParse(v.c_str());
if(!jb)
{
delete ja;
return NULL;
}
ja->value.push_back(jb);
q ++;
p = q;
break;
}
q++;
} // while
} // while
}
return NULL;
}
return NULL;
}
// -------
JsonBase & JsonBase::operator[](string key)
{
if (Type() == JsonTypeObject)
{
JsonObject * jo = (JsonObject *)this;
if(jo->value.find(key) == jo->value.end())throw range_error(key + " not found");
return *jo->value[key];
}
else
throw runtime_error("node is not an object");
}
JsonBase & JsonBase::operator[](unsigned int index)
{
if (Type() == JsonTypeArray)
{
JsonArray * ja = (JsonArray *)this;
if(index >=ja->value.size())throw range_error("out of rang");
return *ja->value[index];
}
else
throw runtime_error("node is not an array");
}
// ------
int main()
{
/*
ifstream input("test.txt");
string json;
string line;
JsonBase * j;
while(getline(input,line))
{
if(line=="")
{
cout << json << endl;
cout << "..." << endl;
j = JsonParse(json.c_str());
json = "";
if(j) cout << j->Serialize() << endl;
else cout << "error" << endl;
cout << "----------------" << endl;
}
else
{
json += line;
}
}
//*/
//*
JsonBase * j;
j = JsonParse("{a:{d:4,e:[2,3,4,5,6]},b:2,c:3}");
try{
cout << (*j)["a"]["e"].Serialize() << endl;
}catch(exception & e){
cout << e.what() << endl;
}
//*/
return 0;
}