手写JSON解析器因嵌入式需求、极简依赖、教学或定制语义(如忽略注释、容忍末尾逗号);不支持Unicode转义、UTF-8校验及NaN/Infinity;通过in_string标记跳过字符串内空白与注释;递归下降解析,分token查看与消费;数字解析需手动处理科学计数法并避免精度丢失。

为什么不用第三方库而手写 JSON 解析器
因为需要嵌入式环境、极简依赖、教学理解或定制化语义(比如忽略注释、容忍末尾逗号)。标准 std::string + std::vector + 递归下降就能覆盖大部分合法 JSON 的核心结构,但必须明确:不处理 Unicode 转义(如 \u00E9)、不校验 UTF-8 编码、不支持 NaN/Infinity——这些是合规性边界,不是 bug。
如何识别并跳过空白与注释(非标准但常见需求)
JSON 标准不支持注释,但很多配置场景会加 // 或 /* */。解析前预处理容易出错(比如字符串内出现 //),更稳妥的做法是在 token 扫描阶段动态跳过:
- 遇到
/时, peek 下一个字符:若是/,则跳到行尾;若是*,则跳到下一个*/ - 跳过
、\t、\n、\r时,注意别跳过字符串内部的换行(字符串未闭合前不跳) - 用一个布尔变量
in_string标记当前是否在双引号内,避免误判
parse_value() 如何递归处理嵌套结构
JSON 值可以是字符串、数字、布尔、null、数组或对象,其中数组和对象会递归调用 parse_value()。关键点在于分清“读取 token”和“消费 token”:
- 先用
peek_char()查看下一个非空白字符,决定分支:'{'→ 对象,'['→ 数组,'"'→ 字符串,'t'/'f'→ bool,'n'→ null,数字开头 → number - 每个分支里,调用对应函数(如
parse_object())后,必须确保读取并跳过结束符('}'或']'),否则上层递归会卡住 - 错误恢复弱:遇到意外字符(如
{ "a": 1, }中的多余逗号),直接返回空值或抛异常,不尝试跳过重试
数字解析为何不能用 std::stod() 直接转换
因为 std::stod() 在输入非法时抛异常,且无法控制精度丢失(如大整数转 double 后变成 9007199254740993.0 → 9007199254740992.0)。实际做法是分段处理:
立即学习“C++免费学习笔记(深入)”;
- 先扫描连续数字字符(含
-、.、e/E),提取完整字面量子串 - 检查是否含小数点或指数:有则走浮点解析(用
std::strtod()+ errno 判断溢出);否则走整数解析(用std::strtoll(),并判断是否超出int64_t范围) - 若字面量过长(如 1000 位数字),直接标记为
JSON_NUMBER_TOO_LONG错误,不尝试转换
最易被忽略的是科学计数法中的符号处理:"1e-5" 和 "1e+5" 都合法,但 "1e5" 的 e 后面没符号也合法——解析时要区分 e 后是否有 +/-,再决定是否读取下一位数字。











