如何从传入数据流中检测JSON字符串起止并提取完整JSON
硬件流式JSON数据截断/拼接场景处理方案
核心思路是维护持久化接收缓冲区+逐字符状态机扫描,完全规避简单大括号计数、正则匹配无法处理字符串内特殊字符、嵌套结构的问题。
基础处理流程
- 初始化一个全局留存缓冲区,每次硬件推送新的数据块时,先将数据块完整追加到缓冲区末尾
- 从缓冲区当前未处理的起始位置开始逐字符扫描,全程跟踪三个核心状态:
- 字符串包裹状态:标记当前是否处于字符串内部,区分双引号、单引号两种包裹格式,同时识别转义符
\,被转义的引号不会被判定为字符串结束 - 大括号嵌套层级:仅当不在字符串内部时,遇到
{则层级+1,遇到}则层级-1 - 转义标记:标记下一个字符是否为转义内容,跳过对应的状态判断
- 字符串包裹状态:标记当前是否处于字符串内部,区分双引号、单引号两种包裹格式,同时识别转义符
- 扫描过程中如果大括号层级降到0,说明当前从上次截取终点到当前位置的片段是完整JSON,截取后送入解析队列,更新截取终点到当前位置的下一位,继续向后扫描
- 单次扫描到缓冲区末尾后,将截取终点之后的剩余内容留在缓冲区中,等待下一批数据到来后重复上述流程
两类异常场景的适配逻辑
- 不完整JSON截断场景:如果扫描到缓冲区末尾都没有出现大括号层级归0的情况,说明当前缓冲区内容全为未完成片段,全部留存不做解析,等后续数据补全后再扫描
- 多JSON拼接场景:扫描过程中每触发一次大括号层级归0就截取一个完整JSON,连续拼接的多个对象会被依次切分,不会出现漏解析、粘包解析错误的问题
注意:绝对不要用正则表达式做JSON边界切分,正则无法正确识别嵌套结构、字符串内的大括号、转义引号这类边界情况,数据结构复杂或者传输压力大时必然出现解析错误。
核心逻辑参考实现
// 全局持久化缓冲区与状态标记 let receiveBuffer = ''; let inString = null; // null=不在字符串内,'"'=双引号字符串内,"'"=单引号字符串内 let isEscaped = false; let braceDepth = 0; let scanStart = 0; function processNewChunk(chunk) { receiveBuffer += chunk; const parsedValidJsons = []; for (let i = scanStart; i < receiveBuffer.length; i++) { const currChar = receiveBuffer[i]; // 处理转义字符,当前字符被转义时跳过状态判断 if (isEscaped) { isEscaped = false; continue; } // 字符串内部状态处理 if (inString) { if (currChar === '\\') { isEscaped = true; continue; } if (currChar === inString) { inString = null; } continue; } // 非字符串内部的结构判断 if (currChar === '"' || currChar === "'") { inString = currChar; continue; } if (currChar === '{') { braceDepth++; continue; } if (currChar === '}') { braceDepth--; // 大括号深度归0,命中完整JSON边界 if (braceDepth === 0) { const jsonSegment = receiveBuffer.slice(scanStart, i + 1); parsedValidJsons.push(jsonSegment); scanStart = i + 1; } } } // 清理已解析完成的缓冲区内容,重置扫描状态 receiveBuffer = receiveBuffer.slice(scanStart); scanStart = 0; inString = null; isEscaped = false; braceDepth = 0; // 返回本轮解析出的所有完整JSON字符串,可直接送入JSON解析逻辑 return parsedValidJsons; }
上述实现支持单/双引号字符串、字符串内包含大括号、任意深度对象嵌套的场景,完全匹配硬件传输的复杂JSON结构需求。
内容的提问来源于stack exchange,提问作者s k
相关产品推荐
相关产品推荐

