C++如何不转字符串即可裁剪istream输入流末尾的无效内容?
流模式下裁剪JSON末尾无效内容的实现方法
你已经定位到了顶层JSON对象的起始{,后续只要维护大括号配对计数、字符串和转义状态,读到配对的顶层}时直接截断流即可,全程不需要将JSON整体转为字符串,内存占用极低。
具体实现方案
方案1:自定义过滤流包装(适配支持流输入的反序列化器)
通过继承std::streambuf实现一个过滤缓冲层,包裹原有的std::ifstream,在读取逻辑中加入状态判断,自动在JSON结束位置返回EOF,反序列化器感知不到底层逻辑差异,直接传入包装后的流即可。
示例代码:
#include <streambuf> #include <istream> #include <fstream> #include <limits> class JsonTrimStreambuf : public std::streambuf { private: std::streambuf* underlying; int brace_count = 1; // 已经定位到起始{,初始层数为1 bool in_string = false; bool is_escaped = false; char buf; // 单字符缓冲,无额外内存开销 protected: int underflow() override { if (brace_count == 0) { return traits_type::eof(); } int ch = underlying->sbumpc(); if (ch == traits_type::eof()) { return traits_type::eof(); } if (is_escaped) { is_escaped = false; } else if (ch == '\\' && in_string) { is_escaped = true; } else if (ch == '"') { in_string = !in_string; } else if (!in_string) { if (ch == '{') { brace_count++; } else if (ch == '}') { brace_count--; } } buf = traits_type::to_char_type(ch); setg(&buf, &buf, &buf + 1); return ch; } public: explicit JsonTrimStreambuf(std::streambuf* buf) : underlying(buf) {} }; // 使用示例 int main() { std::ifstream myIfstream("your_file.txt"); // 原有裁剪开头无效内容的逻辑 myIfstream.ignore(std::numeric_limits<std::streamsize>::max(), '{'); myIfstream.unget(); // 构造过滤流 JsonTrimStreambuf trim_buf(myIfstream.rdbuf()); std::istream json_in(&trim_buf); // 直接把json_in传给你的JSON反序列化器即可,会自动在JSON结束位置停止 // 例如:auto json_obj = nlohmann::json::parse(json_in); return 0; }
方案2:逐字符喂入反序列化器(适配支持逐字符输入的反序列化器)
如果你的反序列化器提供逐字符处理的接口,可以不用自定义流,直接在读取字符时维护上述状态,直到顶层}出现后停止喂入即可:
// 假设反序列化器有类似feed(char ch)的逐字符输入接口 int brace_count = 1; bool in_string = false; bool is_escaped = false; char ch; while (myIfstream.get(ch)) { if (is_escaped) { is_escaped = false; } else if (ch == '\\' && in_string) { is_escaped = true; } else if (ch == '"') { in_string = !in_string; } else if (!in_string) { if (ch == '{') { brace_count++; } else if (ch == '}') { brace_count--; } } // 喂入字符给反序列化器 deserializer.feed(ch); if (brace_count == 0) { break; } } // 调用反序列化器结束处理的接口即可
注意事项
- 如果你的JSON顶层结构是数组而非对象,可以把逻辑中的
{/}替换为[/],适配数组结构的配对 - 该方案默认输入中的JSON是语法合法的,如果存在语法错误可能提前截断或者计数异常,可以根据需求加入错误处理逻辑
内容的提问来源于stack exchange,提问作者Le Canard fou
相关产品推荐
相关产品推荐

