她说:JSON 没错,但就是 parse 不过?我懂了!
技术纯享版:《不规范 JSON 怎么办?三种修复思路+代码实现》
开篇:夜色渐浓,佳人亦在
那天晚上,办公室的灯已经灭了大半,只剩几个工位发出轻轻的蓝光。中央空调早就熄了,但显示器的热度依然在屏幕前形成一圈圈淡淡的光晕。
我坐在靠窗的位置,刚把代码提交推送完,正打算收键盘走人。
这时,小语走过来,端着还冒着热气的速溶咖啡——她果然又是那个留下来最晚的人之一。
“诶~”她蹲在我旁边的桌子边上,语气带着一丝挫败,“你这边有没有遇到 JSON 字符串明明格式看着没错,却死活 JSON.parse
不过的情况?”
一个普通的错误,却不是普通的崩溃
原来她在调试一个用户日志上传模块,前端接收到的日志数据是从后端来的 JSON 字符串。
问题出在一个看似再平常不过的解析操作上——
const logData = JSON.parse(incomingString);
可是控制台总是报错:Unexpected token
。数据一眼看去也没问题,{'name': 'Tom', 'age': 30}
—— 结构清晰,属性齐全,但偏偏就是“坏掉了”。
她抿了一口咖啡,苦笑,“我知道是引号的问题,可这种数据是从破旧的系统里吐出来的,量还特别大,我不可能一个个手动改。”
风起 · JSON.parse 不是万灵药
我们一起回顾了她的实现方式。她用的是最基础的 JSON.parse()
,这是我们在项目里默认的处理方式——简单、直接、快速。
但这个方法对 JSON 格式的要求极其严格:
- 只能使用双引号
"
- 属性名必须加引号
- 不容忍任何额外字符或注释
一旦出现诸如单引号、缺少逗号、多余空格这些“微小过失”,就直接抛错了。
小语叹气,“很多时候这些 JSON 是设备端拼出来的,不规范,又没有错误提示,我根本不知道该怎么修。”
我翻了翻之前的代码,从夹缝中找出来一张破旧的黄皮纸,我们俩一起瞅了上去,看到上面写着
function tryParseJSON(jsonString) {
try {
return JSON.parse(jsonString);
} catch (e) {
// 尝试简单修复:去除可能的多余字符
const cleaned = jsonString.replace(/[^\x20-\x7E]/g, '').trim();
try {
return JSON.parse(cleaned);
} catch (e2) {
console.error("无法解析JSON:", e2);
return null;
}
}
}
下面备注了一行小字:此法在一些更轻量的场景里,做一些“简陋修复“,对于简单的问题有时能奏效,但对于更复杂的错误,比如混合了单引号和双引号的情况,只能再实现另一个方法可以做更针对性的修复方法:
function fixQuotes(jsonString) {
// 将单引号替换为双引号(简单情况)
return jsonString.replace(/'/g, '"');
}
小语感叹一声:“没有更好的了吗?”
解决篇 · 来自大佬的一句话
恰好这时,阿杰从会议室出来,耳机还挂在脖子上。
他听了一耳朵后随口说了句:“你们试过 jsonrepair
吗?那玩意能把坏 JSON 修回来,就像修车。”
“json... repair?”小语一脸困惑。
我忽然想起,之前有个日志监控服务也碰到类似的问题,当时就是用了这个库一把梭。
我打开编辑器,快速翻出来了这一段:
npm install jsonrepair
const { jsonrepair } = require('jsonrepair');
const damaged = "{name: 'John', age: 30}";
const fixed = jsonrepair(damaged); // => {"name":"John","age":30}
const obj = JSON.parse(fixed);
小语凑过来看了一眼,眼睛一亮:“它真的把引号补好了?”
我点头。这个工具是为了解决类似“非标准 JSON”问题的,它会尽可能地补全缺失引号、逗号,甚至处理 Unicode 异常字符。
当然,也不是所有情况都适用。
比如碰到乱码或者非法嵌套结构,jsonrepair
有时也会无能为力。这时可以退一步——用更宽松的解析器,比如 JSON5
:
const JSON5 = require('json5');
const result = JSON5.parse("{name: 'John', age: 30}"); // 也能解析
我看着认真学习的小语,语重心长的讲道:它不是修复,而是扩展 JSON 标准,让一些非标准写法也能解析(JSON5 能容忍的内容包括:单引号、尾逗号、注释、未加引号的属性名、十六进制、科学计数法等数字格式),
接着我们还讨论了更复杂的修复方式,比如用正则处理批量日志,甚至用 AST 工具逐步构建 JSON 树。但那是更远的故事了。
面对当前的问题,我们准备搞一套组合拳:
function parseJson(jsonString) {
// 第一步:尝试标准JSON解析
try {
return JSON.parse(jsonString);
} catch (e) {
console.log("标准JSON解析失败,尝试修复...");
// 第二步:尝试使用jsonrepair修复
try {
const { jsonrepair } = require('jsonrepair');
const fixedJson = jsonrepair(jsonString);
return JSON.parse(fixedJson);
} catch (e2) {
console.log("修复失败,尝试使用JSON5解析...");
// 第三步:尝试使用JSON5解析
try {
const JSON5 = require('json5');
return JSON5.parse(jsonString);
} catch (e3) {
// 最后:如果所有方法都失败,返回错误信息
console.error("所有解析方法都失败了:", e3);
throw new Error("无法解析JSON数据");
}
}
}
}
结局
一段时间后,小语在前端监控日志里贴了段截图:原本一天上千条的 parse error
错误,几乎消失了。
她补了一句:“终于不用再一个个点开调日志了。”
我回头看她的工位,屏幕亮着,浏览器里是一个模拟器页面,console 正在缓缓输出内容。
她突然抬起头看着我,问道:“AST是什么?听说也能实现json修复?”
来源:juejin.cn/post/7506754146894168118