C++解析.ipynb文件只需用nlohmann/json等JSON库读取UTF-8编码的JSON内容,提取cells数组中cell_type为"code"的source字符串数组并拼接,注意处理BOM、换行及nbformat版本差异。

直接读取 .ipynb 文件就是读 JSON
IPython Notebook 文件(.ipynb)本质是 UTF-8 编码的 JSON 文本,不是二进制格式。C++ 没有原生支持,但不需要“解析 notebook”专用库——你只需要一个轻量 JSON 解析器,比如 nlohmann/json 或 jsoncpp,然后按标准 JSON 流程读取。
常见错误是试图用 fstream 逐行读取后手动拆字段,或者误以为要调用 Jupyter 内核。其实只要能读 JSON,就能拿到所有 cell、代码、Markdown、输出结果(如果已保存)。
- 用
std::ifstream以std::ios::binary模式打开(避免 Windows 下换行符截断),再转为 string 传给 JSON 库 - 必须检查
nbformat字段(如"nbformat": 4),老版本结构略有差异,cells字段位置不变,但某些元数据键名可能不同 - 注意:未执行过的 notebook 的
outputs和execution_count字段通常为空数组或null,别假设它们一定存在
nlohmann/json 读取示例(推荐)
nlohmann/json 上手最快,header-only,C++11 起支持,配合现代 C++ 的 auto 和范围 for 很直观。它会把 .ipynb 映射成嵌套的 json 对象,cells 是数组,每个元素是 cell 对象。
关键字段路径:
立即学习“C++免费学习笔记(深入)”;
- notebook 元数据:
j["metadata"] - 所有 cell:
j["cells"](JSON array) - 第 i 个 cell 的类型:
j["cells"][i]["cell_type"](值为"code"或"markdown") - 代码内容:
j["cells"][i]["source"]是字符串数组(每行一元素),需join处理 - 执行结果(若已保存):
j["cells"][i]["outputs"],其中"text/plain"或"application/json"在data字段下
示例片段(不带错误处理):
#include <nlohmann/json.hpp>
#include <fstream>
#include <iostream>
#include <string>
using json = nlohmann::json;
std::ifstream f("example.ipynb");
json j = json::parse(f);
for (auto& cell : j["cells"]) {
std::string type = cell["cell_type"];
if (type == "code") {
std::string code = cell["source"].dump(); // 或遍历 source 数组拼接
std::cout << "CODE: " << code << "\n";
}
}
jsoncpp 与编码/换行陷阱
用 jsoncpp 时容易掉坑:它默认用 std::string 存储 JSON 字符串,但若文件含 BOM 或混合 \r\n,Json::CharReaderBuilder 可能解析失败,报错类似 "Syntax error when parsing value at line X"。
- 务必先用
std::ifstream以std::ios::binary打开,读全文件到std::string,再用erase去掉开头 BOM(\xEF\xBB\xBF) -
source字段里每行末尾自带\n(即使原始 cell 是单行),拼接时别重复加换行 -
jsoncpp不自动转换 Unicode 转义(如\u4f60),但nlohmann/json默认支持,中文 notebook 推荐后者
不建议走 Python 绑定或子进程方案
有人想用 pybind11 调 nbformat.read(),或用 std::system("jupyter nbconvert --to json") 中转。这两种方式都引入了非必要依赖和不确定性:
- 前者要求目标机器装 Python + nbformat,部署成本陡增,且异常难调试(C++ 异常 vs Python 异常)
- 后者依赖
jupyterCLI 可用,路径、环境变量、版本兼容(如 nbformat v5 vs v4)全是隐性风险 - 纯 C++ JSON 解析在内存中完成,毫秒级;子进程启动+磁盘 IO 至少几十毫秒,还可能被杀毒软件拦截
真正卡点其实是 notebook 输出内容的结构多样性(比如 execute_result vs error vs display_data),而不是读取本身。先确保能稳定提取 source,再按需扩展对 outputs 的 schema 分支处理。


















