Skip to content

A tool that can create and parse .json format files

License

Notifications You must be signed in to change notification settings

e2hang/JsonParser

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

E2hangJson

一个基于 C++20 开发的高性能、易用的 JSON 解析与序列化库。

🚀 特性

  • 现代 C++ 设计:充分利用 C++20 特性(如 std::source_location 等)。
  • 灵活的 API:支持类似 Python 字典和列表的操作方式。
  • 高性能:支持流式解析和高效的字符串序列化。
  • 工业级健壮性:内置详细的错误报告机制,定位错误发生的行、列及偏移量。

💻 快速开始

示例代码

创建一个 test.cpp 来演示如何使用本库:

#include <iostream>
#include "JsonParser.h"
#include "JsonSerializer.h"
#include "JsonValue.h"

int main() {
    // 1. 手动构建 JSON 对象
    JsonValue root(JsonValue::Type::Map);
    root["name"] = "E2hang";
    root["version"] = 1.0;
    root["features"] = JsonValue::Type::List;
    root["features"].push_back("Fast");
    root["features"].push_back("Modern");

    // 2. 序列化为字符串
    std::string jsonStr = JsonSerializer::serialize(root, 4); // 4空格缩进
    std::cout << "Serialized JSON:\n" << jsonStr << std::endl;

    // 3. 解析 JSON 字符串
    JsonParser parser(jsonStr);
    try {
        JsonValue parsedValue = parser.parse();
        std::cout << "Parsed Name: " << parsedValue["name"].asString() << std::endl;
    } catch (const JsonError& e) {
        std::cerr << "Parse Error: " << e.to_string() << std::endl;
    }

    return 0;
}

E2hangJson 开发者指南

E2hangJson 是一个简洁且功能完备的 C++20 JSON 处理库。它提供了类似于原生数据类型的操作体验,支持对象(Object)、数组(Array)、字符串(String)、数值(Number)、布尔值(Bool)以及空值(Null)。

核心类说明

类名 说明
JsonValue 核心容器。表示一个 JSON 节点,支持递归嵌套。
JsonParser 解析器。将字符串转换为 JsonValue 对象。
JsonSerializer 序列化器。将 JsonValue 对象转换为格式化的字符串。
JsonError 异常类。提供错误代码及详细的行列定位。

📂 项目结构

JsonParse/
├── include/             # 头文件 (.h)
│   ├── JsonValue.h      # 核心数值类型定义
│   ├── JsonParser.h     # 解析逻辑
│   ├── JsonSerializer.h # 序列化逻辑
│   └── JsonError.h      # 异常处理
├── src/                 # 源代码 (.cpp)
├── test/                # 测试用例
├── E2hangJson.dll       # 运行时库
└── E2hangJson.lib       # MSVC 导入库


🛠 接口使用说明

1. 构建与赋值

你可以通过多种方式初始化 JsonValue,操作起来就像使用原生变量:

// 基础类型
JsonValue name("E2hang");
JsonValue age(25);
JsonValue isDeveloper(true);
JsonValue data(nullptr); // JSON null

// 容器类型初始化
JsonValue obj(JsonValue::Type::Map);
JsonValue arr(JsonValue::Type::List);

2. 对象与数组操作

本库重载了 [] 运算符,支持链式访问。

对象操作:

JsonValue user;
user["id"] = 1001;
user["profile"]["bio"] = "Keep coding.";
user["tags"] = JsonValue::Type::List; 

// 检查是否存在某个键
if (user.is_map()) { /* ... */ }

数组操作:

JsonValue list(JsonValue::Type::List);
list.push_back(1);
list.push_back("Second");
list.push_back(JsonValue::Type::Map);

// 访问
std::cout << list[1].asString() << std::endl; // 输出: Second

3. 类型安全的数据提取

为了保证安全,提取数据前可以进行类型检查,随后使用 as... 系列函数:

if (val.is_string()) {
    std::string s = val.asString();
}

if (val.is_double() || val.is_bool()) {
    double d = val.asDouble();
    bool b = val.asBool();
}

// 转换为标准库容器
auto mapData = val.asMap();   // 返回 std::map<std::string, JsonValue>
auto vecData = val.asList();  // 返回 std::vector<JsonValue>

4. 解析 JSON 字符串

JsonParser 会对输入的字符串进行语法分析:

std::string raw = R"({"status": "ok", "code": 200})";
JsonParser parser(raw);

try {
    JsonValue root = parser.parse();
    std::cout << root["status"].asString();
} catch (const JsonError& e) {
    // 发生错误时,e 提供详细信息
    std::cerr << "Error: " << e.message() 
              << " at Line: " << e.line() 
              << ", Col: " << e.column() << std::endl;
}

5. 序列化 (生成 JSON 文本)

JsonSerializer 支持美化输出(带缩进)或紧凑输出:

// 参数 2 为缩进空格数。若设为 -1 则生成不带换行的紧凑格式
std::string pretty = JsonSerializer::serialize(root, 4);
std::string compact = JsonSerializer::serialize(root, -1);

其他方法可参考 test/test.cpp


⚠️ 开发注意事项

  1. 异常处理:在调用 asString()asDouble() 等函数时,如果 JsonValue 的实际类型与请求类型不符,库会抛出异常。建议在处理不可信的 JSON 数据时使用 is_...() 进行预检。
  2. 编码说明:库内部处理 std::string。建议在 Windows 下保持源文件为 UTF-8 编码,并在编译时开启 /utf-8 标志,以确保中文字符串正常解析。
  3. 内存模型JsonValue 内部使用递归结构管理内存,支持拷贝构造与移动语义,能够高效地在函数间传递。

🛠 进阶技巧与深度解析

1. 细粒度类型检查

除了基础的 is_string 等,JsonValue 提供了一个 Type 枚举,方便在 switch 语句中使用,这比连续的 if-else 更高效:

switch (val.type()) {
    using enum JsonValue::Type;
    case Map: /* 处理对象 */ break;
    case List:  /* 处理数组 */ break;
    case String: /* 处理字符串 */ break;
    case Number: /* 处理数字 */ break;
    case Bool:   /* 处理布尔 */ break;
    case Null:   /* 处理空值 */ break;
}

2. 字符串转义与 Unicode 处理 (Internal Logic)

JsonParser 内部实现了对 JSON 标准转义字符的支持。如果你需要扩展解析逻辑,可以参考以下机制:

  • 转义解析:支持 \", \\, \/, \b, \f, \n, \r, \t
  • Unicode 支持:通过 parse_hex_4() 接口解析 \uXXXX 格式。它会将 4 位十六进制码点转换为 UTF-8 编码存入 std::string
  • 序列化转义JsonSerializer::escapeString 会自动将字符串中的特殊字符(如换行符、引号)转回转义序列,确保生成的 JSON 文件合法。

3. 流式调试打印

为了方便快速观察数据结构,JsonValue 提供了一个简单的 print() 成员函数,直接将内容输出到标准控制台,这在断点调试时非常有用。

JsonValue root = parser.parse();
root.print(); // 快速查看控制台输出

4. 异常定位原理

当解析失败时,JsonError 不仅仅是一个错误信息。它通过内部计数器维护了解析进度:

  • offset(): 距离文件开头的绝对字符位置。
  • line() / column(): 自动计算行号和列号,帮助开发者在大型 JSON 文件中快速定位坏损节点。

🏗 架构设计

项目遵循解耦设计原则,将数据存储、解析逻辑、展现逻辑完全分离:

  1. 数据层 (JsonValue):采用类似“变体类型”的设计,内部管理一个 std::variant 风格的存储结构,负责内存的分配与回收。
  2. 解析层 (JsonParser):采用 递归下降解析法 (Recursive Descent Parsing)。从 parse_value 开始,根据首字符探测自动分发到 parse_objectparse_array 等子模块。
  3. 表示层 (JsonSerializer):递归遍历树状结构。通过 addIndent 维护当前的缩进深度,生成人类可读的格式化文本。

📝 开发者建议

关于 std::source_location (C++20)

JsonError 的构造函数中,我们利用了 C++20 的 std::source_location。这意味着当库抛出异常时,它能自动记录是库中哪一行源代码触发了错误,这对于库本身的维护者(也就是你)来说是极大的利好。

性能提示

  • 移动语义:在构建大型 JSON 对象时,尽量使用 std::move,例如 root["big_data"] = std::move(another_json_value),以避免深拷贝带来的开销。
  • 预分配:如果你知道一个数组的大小,建议先通过标准库方式处理数据,最后再包装进 JsonValue

🔗 接口一览表 (速查)

函数 功能 备注
push_back(val) 向 Array 末尾添加元素 仅限 Array 类型
size() 返回对象键数或数组长度 通用统计
to_string() 格式化错误报告 JsonError 专属
serialize(val, indent) 静态序列化方法 JsonSerializer 专属
parse() 执行解析并返回 root JsonParser 专属

🛠 编译与安装

1. 开发环境要求

  • 编译器:MSVC (Visual Studio 2022+) 或 GCC (MinGW-w64)
  • 标准:C++20

2. 编译 DLL 库

项目采用动态链接库 (DLL) 形式导出。编译时需定义 JSON_LIBRARY_EXPORT 宏。

使用 MSVC 命令行:

cl /I./include /O2 /std:c++20 /utf-8 /EHsc /DJSON_LIBRARY_EXPORT src/*.cpp /LD /Fe:E2hangJson.dll

3. 链接与使用

在你的项目中引用 E2hangJson.lib(导入库)和头文件。

⚠️ 重要提示(避坑指南): 本库在 Windows 下涉及符号导出。如果你的 DLL 是用 MSVC 编译的,那么测试程序也必须使用 MSVC 编译;混合使用(如用 g++ 链接 MSVC 编译的 DLL)会导致 undefined reference 错误。


编译测试程序 (MSVC)

cl ./test/test.cpp /I./include /std:c++20 /utf-8 /EHsc E2hangJson.lib /Fe:test_app.exe

⚠️ 常见问题排查

1. 链接报错 __imp_... (Undefined Reference)

  • 原因:编译器不匹配或宏定义缺失。
  • 解决:确保库文件和测试程序使用同一工具链。确保在使用 DLL 时不要定义 JSON_LIBRARY_EXPORT

2. 编码问题 C2001: 常量中有换行符

  • 原因:MSVC 默认使用 GBK 读取 UTF-8 文件。
  • 解决:编译命令中添加 /utf-8 参数。

📄 开源协议

MIT License


About

A tool that can create and parse .json format files

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published