轻量化解析 作为轻量化解析器,目标是从 JSON 字符串中提取键值对、嵌套对象 ({}
) 和数组 ([]
),同时维持层级和嵌套关系。实现递归解析格式规整的 JSON 字符串。
项目地址: floraison-io/json-cpp: A minimal JSON parser
支持:
嵌套 JSON 对象(多层花括号)
数组嵌套(数组中可以包含数组或对象)
字符串和基本类型
不支持:
处理转义字符,如 \"
。
键值之间的语法校验,错误恢复。
JSON格式分析 一段标准JSON数据结构如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 { "person" : { "name" : "Alice" , "age" : 25 , "address" : { "city" : "Phoenix" , "zip" : "10001" } } , "primitive" : "triangle" , "employee" : { "name" : "Bob" , "array" : [ 8 , 2 , 4 , 0 , 3 ] , "age" : 22 , "address" : { "city" : "Paris" , "zip" : "11111" } } }
**{}**
双括号表示对象;
**[]**
中括号表示数组;
**""**
双引号内是属性或值;
**:**
冒号表示后者是前者的值(这个值可以是字符串、数字、也可以是另一个数组或对象)
类成员和结构概览 1 2 3 4 5 6 class JSON { std::string jsonStr; std::map<std::string, std::any> key_value; std::vector<JSON*> subJsons; };
JSON对象的构造函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 JSON::JSON (std::string m_jsonStr) { jsonStr = m_jsonStr; normalize (jsonStr); jsonStr = jsonStr.substr (1 , jsonStr.length () - 2 ); while (jsonStr.find_first_of (":" ) != std::string::npos) { jsonStr = jsonStr.substr (jsonStr.find_first_of ("\"" ) + 1 ); std::string key = jsonStr.substr (0 , jsonStr.find_first_of ("\"" )); jsonStr = jsonStr.substr (jsonStr.find_first_of ("\"" ) + 2 ); if (jsonStr[0 ] == '{' ) { int leftBrace = 1 ; int rightBrace = 0 ; int i = 1 ; for (i = 1 ; leftBrace != rightBrace; i++) { if (jsonStr[i] == '{' ) { leftBrace++; } if (jsonStr[i] == '}' ) { rightBrace++; } } std::string subJsonStr = jsonStr.substr (0 , i); jsonStr = jsonStr.substr (i); JSON* subJson = new JSON (subJsonStr); subJsons.push_back (subJson); key_value[key] = subJson; } else if (jsonStr[0 ] == '[' ) { int leftBracket = 1 ; int rightBracket = 0 ; int i = 1 ; for (i = 1 ; leftBracket != rightBracket; i++) { if (jsonStr[i] == '[' ) { leftBracket++; } if (jsonStr[i] == ']' ) { rightBracket++; } } std::string subArrStr = jsonStr.substr (0 , i); std::any subArr = parseArray (subArrStr); key_value[key] = subArr; jsonStr = jsonStr.substr (i + 1 ); } else if (jsonStr[0 ] == '\"' ) { jsonStr = jsonStr.substr (1 ); int i = jsonStr.find_first_of ('\"' ); std::string value = jsonStr.substr (0 , i); key_value[key] = value; jsonStr = jsonStr.substr (i + 1 ); } else { int i = jsonStr.find_first_of (',' ); std::string value = jsonStr.substr (0 , i); key_value[key] = value; jsonStr = jsonStr.substr (i); } } }
去除空格与换行 :
1 2 3 4 5 void JSON::normalize (std::string& str) { str.erase (std::remove_if (str.begin (), str.end (), [](unsigned char c) { return c == ' ' || c == '\n' || c == '\r' ; }), str.end ()); }
解析键值对 :以冒号 :
为标志,持续提取 key,然后根据 value 的起始字符判断类型:
处理嵌套对象/数组的括号匹配 :分别对左右括号计数,保证处理的是完整的 JSON 子串/数组。然后递归调用JSON对象构造函数/parseArray函数。
parseArray 函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 std::vector<std::any> JSON::parseArray (std::string m_arrStr) { std::vector<std::any> arr; std::string arrStr = m_arrStr.substr (1 , m_arrStr.length () - 2 ); arrStr += ',' ; while (arrStr.find_first_of ("," ) != std::string::npos) { if (arrStr[0 ] == '[' ) { int leftBracket = 1 ; int rightBracket = 0 ; int i = 1 ; for (i = 1 ; leftBracket != rightBracket; i++) { if (arrStr[i] == '[' ) { leftBracket++; } if (arrStr[i] == ']' ) { rightBracket++; } } std::string nextArr = arrStr.substr (0 , i); arrStr = arrStr.substr (i + 1 ); arr.push_back (parseArray (nextArr)); continue ; } if (arrStr[0 ] == '{' ) { int leftBrace = 1 ; int rightBrace = 0 ; int i = 1 ; for (i = 1 ; leftBrace != rightBrace; i++) { if (arrStr[i] == '{' ) { leftBrace++; } if (arrStr[i] == '}' ) { rightBrace++; } } std::string subJsonStr = arrStr.substr (0 , i); arrStr = arrStr.substr (i + 1 ); JSON* subJson = new JSON (subJsonStr); subJsons.push_back (subJson); arr.push_back (subJson); continue ; } std::string element = arrStr.substr (0 , arrStr.find_first_of ("," )); element.erase (std::remove_if (element.begin (), element.end (), [](unsigned char c) { return c == '\"' ; }), element.end ()); arr.push_back (element); arrStr = arrStr.substr (arrStr.find_first_of ("," ) + 1 ); } return arr; }
为了方便统一处理每个元素,解析过程中临时加了一个 ,
到数组末尾。
**去除数组的 [
和 ]
**。
循环处理数组中的元素 :