使用C++解析json字符串
解析思路
- 定义枚举类型, 包括
null
, bool
, float
, int
, string
, array
, object
- 顺序遍历字符串, 跳过所有的空白字段, 并根据遇到的第一个有效字符尝试各种解析方案
- 当字符为
n
时, 尝试解析为null
- 当字符为
t
或f
时, 尝试解析为bool
值
- 当字符为
-
或者数字时, 尝试解析为数值
- 当字符为
"
时, 尝试解析为字符串
- 当字符为
[
时, 尝试解析为数组
- 当字符为
{
时, 尝试解析为对象
- 当做完一次完整的解析后, 重复这一步骤即可
定义数据结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| enum class json_type { JSON_NULL, JSON_BOOL, JSON_NUMBER, JSON_INT, JSON_STRING, JSON_ARRAY, JSON_OBJECT }; struct json_value { json_type type; union { bool b; double n; long long i; string* s; vector<json_value*>* a; map<string, json_value*>* o; }; };
|
判断类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| bool is_space(char c) { return c == ' ' || c == '\t' || c == '\n' || c == '\r'; }
void skip_space() { while (pos < len && is_space(input[pos])) pos++; }
bool is_digit(char c) { return c >= '0' && c <= '9'; }
bool is_alpha(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
|
尝试解析
首字母为n, 尝试解析为null
根据首字母的类型, 尝试不同的解析方案
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 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
| json_value* parse_null() { if (pos + 3 < len && input[pos] == 'n' && input[pos + 1] == 'u' && input[pos + 2] == 'l' && input[pos + 3] == 'l') { pos += 4; json_value* v = new json_value(); v->type = json_type::JSON_NULL; return v; } else return nullptr; }
json_value* parse_bool() { if (pos + 3 < len && input[pos] == 't' && input[pos + 1] == 'r' && input[pos + 2] == 'u' && input[pos + 3] == 'e') { pos += 4; json_value* v = new json_value(); v->type = json_type::JSON_BOOL; v->b = true; return v; } else if (pos + 4 < len && input[pos] == 'f' && input[pos + 1] == 'a' && input[pos + 2] == 'l' && input[pos + 3] == 's' && input[pos + 4] == 'e') { pos += 5; json_value* v = new json_value(); v->type = json_type::JSON_BOOL; v->b = false; return v; } else return nullptr; }
json_value* parse_number() { int start = pos; bool is_float = false; if (input[pos] == '-') pos++; if (input[pos] == '0') pos++; else { while (pos < len && is_digit(input[pos])) pos++; } if (pos < len && input[pos] == '.') { is_float = true; pos++; while (pos < len && is_digit(input[pos])) pos++; } if (pos < len && (input[pos] == 'e' || input[pos] == 'E')) { is_float = true; pos++; if (pos < len && (input[pos] == '+' || input[pos] == '-')) pos++; while (pos < len && is_digit(input[pos])) pos++; } if (pos > start) { json_value* v = new json_value(); string num_str(input + start, pos - start); if (is_float) { v->type = json_type::JSON_NUMBER; v->n = stod(num_str); } else { v->type = json_type::JSON_INT; v->i = stoll(num_str); } return v; } else return nullptr; }
json_value* parse_string() { if (input[pos] == '"') { pos++; int start = pos; while (pos < len && input[pos] != '"') pos++; if (pos < len && input[pos] == '"') { pos++; json_value* v = new json_value(); v->type = json_type::JSON_STRING; v->s = new string(input + start, pos - start - 1); return v; } else return nullptr; } else return nullptr; }
json_value* parse_array() { if (input[pos] == '[') { pos++; skip_space(); json_value* v = new json_value(); v->type = json_type::JSON_ARRAY; v->a = new vector<json_value*>(); if (input[pos] == ']') { pos++; return v; } while (true) { json_value* elem = parse_value(); if (elem) { v->a->push_back(elem); skip_space(); if (input[pos] == ',') { pos++; skip_space(); } else if (input[pos] == ']') { pos++; return v; } else { delete v; return nullptr; } } else { delete v; return nullptr; } } } else return nullptr; }
json_value* parse_object() { if (input[pos] == '{') { pos++; skip_space(); json_value* v = new json_value(); v->type = json_type::JSON_OBJECT; v->o = new map<string, json_value*>(); if (input[pos] == '}') { pos++; return v; } while (true) { json_value* key = parse_string(); if (key) { string key_str = *(key->s); delete key; skip_space(); if (input[pos] == ':') { pos++; skip_space(); json_value* value = parse_value(); if (value) { v->o->insert({ key_str, value }); skip_space(); if (input[pos] == ',') { pos++; skip_space(); } else if (input[pos] == '}') { pos++; return v; } else { delete v; return nullptr; } } else { delete v; return nullptr; } } else { delete v; return nullptr; } } else { delete v; return nullptr; } } } else return nullptr; }
|
解析入口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| json_value* parse_value() { skip_space(); if (input[pos] == 'n') return parse_null(); else if (input[pos] == 't' || input[pos] == 'f') return parse_bool(); else if (input[pos] == '-' || is_digit(input[pos])) return parse_number(); else if (input[pos] == '"') return parse_string(); else if (input[pos] == '[') return parse_array(); else if (input[pos] == '{') return parse_object(); else return nullptr; }
|
解析出一个字段, 就创建一个json_value
, 并将其关联到根节点中, 遍历根节点, 就能得到整个json
的所有字段及其值