之前写过一个JSON解析器,仅能解析简单对象,且不支持数组解析,这次进行改进升级。这个解析器遵从按需解析且不分配内存的原则。精简但是功能齐全,解析器的特点是快速,方便。详见代码:
//================================================
// Copyright (c) 2016 周仁锋. All rights reserved.
// ye_luo@qq.com
//================================================
#ifndef _CJSONPARSER_H_
#define _CJSONPARSER_H_
#include <string>
#include <map>
#include <vector>
using namespace std;
/**
* @brief JSON 解析器
*/
class CJsonParser {
public:
//! 默认构造函数
CJsonParser();
//! 指定字符串构造
CJsonParser(const char* content);
//! 使用指定长度的字符串构造
CJsonParser(const char* content, int length);
//! 解析指定字符串
bool Parse(const char* content, int length);
//! 判断是否包含指定值
bool IsContain(const char* name);
//! 获取数组节点数组大小
int GetCount();
//! 获取节点内指定名称的值
CJsonParser GetValue(const char* name);
//! 获取数组节点内指定的值
CJsonParser GetValue(int index);
public:
//! 是否为空节点
bool IsEmpty() { return m_sValue.type == SValue::NIL; }
//! 是否为布尔类型节点
bool IsBool() { return m_sValue.type == SValue::BOOL; }
//! 是否为数字类型节点
bool IsNumber() { return m_sValue.type == SValue::NUMBER; }
//! 是否为字符串类型节点
bool IsString() { return m_sValue.type == SValue::STRING; }
//! 是否为对象类型节点
bool IsObject() { return m_sValue.type == SValue::OBJECT; }
//! 是否为数组类型节点
bool IsArray() { return m_sValue.type == SValue::ARRAY; }
//! 转换为布尔类型
bool AsBool() { return m_sValue.bValue; }
//! 转换为整型类型
int AsInt() { return (int)m_sValue.fValue; }
//! 转换为浮点类型
float AsFloat() { return m_sValue.fValue; }
//! 转换为字符串类型
string AsString() { return string().append(m_sValue.pValue, m_sValue.length); }
private:
//! JSON 值泛定义
typedef struct _SValue {
enum { NIL, BOOL, NUMBER, STRING, OBJECT, ARRAY } type;
int length;
union {
bool bValue;
float fValue;
const char* pValue;
};
} SValue;
//! 解析当前元素
bool Parse();
//! 解析对象字符串
void ParseObject(const char* data, int length);
//! 解析数组字符串
void ParseArray(const char* data, int length);
//! 解析数字字符串
void ParseNumber(const char* data, int length);
//! 解析 JSON 值
CJsonParser ParseValue(const char* data, int length);
private:
//! JSON 值
SValue m_sValue;
//! JSON 内部子元素
map<string, CJsonParser> m_mapValues;
//! JSON 内部数组
vector<CJsonParser> m_vecValues;
};
#endif
C++实现部分
//================================================
// Copyright (c) 2016 周仁锋. All rights reserved.
// ye_luo@qq.com
//================================================
#include "CJsonParser.h"
#include <cstdlib>
#include <cstring>
using namespace std;
/**
* 构造函数
*/
CJsonParser::CJsonParser() {
m_sValue.type = SValue::NIL;
m_sValue.length = 0;
m_sValue.pValue = 0;
}
/**
* 构造函数
*/
CJsonParser::CJsonParser(const char* content) {
m_sValue.length = strlen(content);
m_sValue.pValue = content;
Parse();
}
/**
* 构造函数
*/
CJsonParser::CJsonParser(const char* content, int length) {
m_sValue.length = length;
m_sValue.pValue = content;
Parse();
}
/**
* 解析指定字符串
*/
bool CJsonParser::Parse(const char* content, int length) {
m_sValue.length = length;
m_sValue.pValue = content;
m_mapValues.clear();
m_vecValues.clear();
return Parse();
}
/**
* 判断是否包含指定值
*/
bool CJsonParser::IsContain(const char* name) {
return m_mapValues.find(name) != m_mapValues.end();
}
/**
* 获取数组节点数组大小
*/
int CJsonParser::GetCount() {
return m_vecValues.size();
}
/**
* 获取节点内指定名称的值
*/
CJsonParser CJsonParser::GetValue(const char* name) {
if (m_sValue.type == SValue::OBJECT) {
map<string, CJsonParser>::iterator iter = m_mapValues.find(name);
if (iter != m_mapValues.end()) {
iter->second.Parse();
return iter->second;
}
}
return CJsonParser();
}
/**
* 获取数组节点内指定的值
*/
CJsonParser CJsonParser::GetValue(int index) {
if (m_sValue.type == SValue::ARRAY) {
if (index >= 0 && index < (int)m_vecValues.size()) {
m_vecValues[index].Parse();
return m_vecValues[index];
}
}
return CJsonParser();
}
/**
* 解析当前元素
*/
bool CJsonParser::Parse() {
m_sValue.type = SValue::NIL;
int beg = 0;
int end = m_sValue.length - 1;
const char* data = m_sValue.pValue;
while (data[beg] == ' ' || data[beg] == '\t' || data[beg] == '\r' || data[beg] == '\n') ++beg;
while (data[end] == ' ' || data[end] == '\t' || data[end] == '\r' || data[end] == '\n') --end;
if (beg >= end) return false;
// 依次判断类型
if (data[beg] == '{' && data[end] == '}') {
m_sValue.type = SValue::OBJECT;
m_sValue.length = end - beg + 1;
ParseObject(data + beg, m_sValue.length);
return true;
}
if (data[beg] == '[' && data[end] == ']') {
m_sValue.type = SValue::ARRAY;
m_sValue.length = end - beg + 1;
ParseArray(data + beg, m_sValue.length);
return true;
}
if (data[beg] == '-' || (data[beg] >= '0' && data[beg] <= '9')) {
m_sValue.type = SValue::NUMBER;
m_sValue.length = end - beg + 1;
ParseNumber(data + beg, m_sValue.length);
return true;
}
if (data[beg] == '"' && data[end] == '"') {
m_sValue.type = SValue::STRING;
m_sValue.length = end - beg - 1;
m_sValue.pValue = &data[beg + 1];
return true;
}
if ((data[beg + 0] == 't' || data[beg + 0] == 'T') &&
(data[beg + 1] == 'r' || data[beg + 1] == 'R') &&
(data[beg + 2] == 'u' || data[beg + 2] == 'U') &&
(data[beg + 3] == 'e' || data[beg + 3] == 'E')) {
m_sValue.type = SValue::BOOL;
m_sValue.length = 0;
m_sValue.bValue = true;
return true;
}
if ((data[beg + 0] == 'f' || data[beg + 0] == 'F') &&
(data[beg + 1] == 'a' || data[beg + 1] == 'A') &&
(data[beg + 2] == 'l' || data[beg + 2] == 'L') &&
(data[beg + 3] == 's' || data[beg + 3] == 'S') &&
(data[beg + 4] == 'e' || data[beg + 4] == 'E')) {
m_sValue.type = SValue::BOOL;
m_sValue.length = 0;
m_sValue.bValue = false;
return true;
}
if ((data[beg + 0] == 'n' || data[beg + 0] == 'N') &&
(data[beg + 1] == 'u' || data[beg + 1] == 'U') &&
(data[beg + 2] == 'l' || data[beg + 2] == 'L') &&
(data[beg + 3] == 'l' || data[beg + 3] == 'L')) {
m_sValue.type = SValue::NIL;
m_sValue.length = 4;
m_sValue.pValue = &data[beg];
return true;
}
return false;
}
/**
* 解析对象字符串
*/
void CJsonParser::ParseObject(const char* data, int length) {
int index = 0;
while (index < length) {
while (index < length && data[index++] != '"');
int nameOffset = index;
while (index < length && data[index++] != '"');
int nameSize = index - nameOffset - 1;
if (nameSize > 0) {
string name = string().append(&data[nameOffset], nameSize);
while (data[index++] != ':');
CJsonParser value = ParseValue(data + index, length - index);
m_mapValues.insert(pair<string, CJsonParser>(name, value));
index = value.m_sValue.pValue - data + value.m_sValue.length;
}
}
}
/**
* 解析数组字符串
*/
void CJsonParser::ParseArray(const char* data, int length) {
int index = 1;
length -= 1;
while (index < length) {
CJsonParser value = ParseValue(data + index, length - index);
m_vecValues.push_back(value);
index = value.m_sValue.pValue - data + value.m_sValue.length;
}
}
/**
* 解析数字字符串
*/
void CJsonParser::ParseNumber(const char* data, int length) {
char temp[256];
length = length > 255 ? 255 : length;
memcpy(temp, data, length);
temp[length] = '\0';
m_sValue.length = 0;
m_sValue.fValue = (float)atof(temp);
}
/**
* 解析 JSON 值
*/
CJsonParser CJsonParser::ParseValue(const char* data, int length) {
int pos = 0;
while (data[pos] == ' ' || data[pos] == '\t' || data[pos] == '\r' || data[pos] == '\n' || data[pos] == ',') ++pos;
int startPosition = pos;
vector<char> keyStack;
keyStack.push_back('#');
while (pos < length) {
const char key = data[pos++];
const char top = keyStack.back();
if (key == '\\') ++pos;
else if (key == '"') {
if (top == '"') keyStack.pop_back();
else keyStack.push_back('"');
if (keyStack.size() == 1) break;
}
else if (key == '{') {
if (top != '"') keyStack.push_back('{');
}
else if (key == '[') {
if (top != '"') keyStack.push_back('[');
}
else if (key == '}') {
if (top == '{') keyStack.pop_back();
if (keyStack.size() == 1) break;
}
else if (key == ']') {
if (top == '[') keyStack.pop_back();
if (keyStack.size() == 1) break;
}
else if (key == ',') {
if (top == '#') --pos;
if (keyStack.size() == 1) break;
}
}
CJsonParser value;
value.m_sValue.pValue = data + startPosition;
value.m_sValue.length = pos - startPosition;
return value;
}
解析示例代码
const char* str = "{\"bValue\":false,\"iValue\":100,\"fValue\":0.12,\"strValue\":\"hello\",\"object\":{\"which\":0,\"finish\":true}}";
CJsonParser parser(str);
bool bValue = parser.GetValue("bValue").AsBool();
std::string strValue = parser.GetValue("strValue").AsString();
if (parser.IsContain("iValue")) {
int iValue = parser.GetValue("iValue").AsInt();
}
if (parser.IsObject("object")) {
int which = parser.GetValue("object").GetValue("which").AsInt();
}