最近在处理一批第三方返回的数据时,我遇到了一个令人头疼的问题:部分 JSON 字符串是破损的,导致在用
JSON.parse()
解析时直接抛出异常。比如有些缺少引号,有些多了逗号,甚至还有嵌套结构不完整的情况。手动修复显然不现实,于是我开始寻找是否有自动修复 JSON 的方案或工具,比如能否在解析前做一些预处理,或者使用更智能的解析库来容错。那面对这些结构混乱的 JSON 数据,我们到底该怎么安全地修复和解析它们呢?
在JavaScript中,正常来说我们都是使用JSON.parse
方法将JSON字符串转换为JavaScript对象。以下是一个简单的示例:
// JSON字符串
const jsonString = '{"name":"Alice","age":25,"city":"Wonderland"}';
// 使用JSON.parse将JSON字符串转换为JavaScript对象
const jsonObject = JSON.parse(jsonString);
// 打印转换后的对象
console.log(jsonObject);
// 访问对象的属性
console.log('Name:', jsonObject.name);
console.log('Age:', jsonObject.age);
console.log('City:', jsonObject.city);
这世界就像一个草台班子,总有些奇奇怪怪的内容,有时候,拿到一段别人写的 JSON,就像接手一锅没煮熟、还撒了一地的乱粥:
- 少了引号
- 多了逗号
- 布尔值写成大写(
True
而不是true
) - 结尾少了大括号……
你拿这种东西直接 JSON.parse()
?对不起,JS 直接报错扔锅!💥
那怎么办?当然是「修粥大法」上场!
我们需要从一个老旧的系统获取数据,而这个系统就有意思了,他的接口返回的是一个纯字符串,如果是纯正json字符串,我转成对象处理也可以,结果他这个返回字符串在转json的时候还报错了,但有时候会出现各种奇怪的错误——单引号代替了双引号,属性名没有加引号,或者多了一些奇怪的逗号或注释……
原生JavaScript方法:手动调锅,自己加水加火加料
我首先尝试了最简单的方法——使用try/catch和一些基本的字符串替换:
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 和 JSON5。这两个库在处理破损的JSON字符串时各有所长。
jsonrepair: 智能修锅机器人!
jsonrepair 是我发现的一个专门用于修复损坏JSON的强大工具。它能处理多种常见的JSON格式错误:
npm install jsonrepair
示例代码
const { jsonrepair } = require('jsonrepair');
const damagedJson = "{'name': 'John', age: 30}";
const fixedJson = jsonrepair(damagedJson);
const obj = JSON.parse(fixedJson);
console.log(obj); // { name: 'John', age: 30 }
这个库能修复什么类型的问题呢?实际上相当广泛:
- 引号问题:将单引号替换为双引号,为未加引号的属性名和字符串值添加引号
- 多余字符:移除注释、尾部逗号和JSON前后的无关字符
- 结构问题:修复缺少闭合的括号或引号
- 编码问题:修复转义字符和Unicode字符
但是,即使是这样强大的工具也有其局限性。对于严重损坏的JSON(如完全无效的语法、深层嵌套的结构错误),jsonrepair 也无能为力。这时候,我们需要另一种解决方案。
JSON5:允许你“不按食谱炒菜”的宽松厨房
在某些情况下,我们需要的不是修复现有的JSON字符串,而是使用一个更宽松的解析器。这就是 JSON5 派上用场的时候:
npm install json5
示例代码
const JSON5 = require('json5');
const looseJson = `{
// 这是一个注释
name: 'Tom',
age: 30,
traits: ["smart", 'funny'],
}`;
const obj = JSON5.parse(looseJson);
console.log(obj);
JSON5 允许:
- 单引号字符串
- 未加引号的属性名
- 尾随逗号
- 注释(单行和多行)
- 更灵活的数字格式、十六进制、科学计数法等数字格式
- 多行字符串
但它也不是万能的。JSON5 不能处理完全不相关的格式或严重结构损坏的数据。
组合使用多种工具
在经过多次尝试后,我发现最有效的方法是根据情况组合使用不同的工具。下面是我最终采用的解决方案:
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数据");
}
}
}
}
虽然有了 jsonrepair 和 JSON5 这样的“补救工具”,但它们永远只是权宜之计。我们应该追本溯源,确保数据的生成过程符合 JSON 标准。如果你需要处理来自用户或第三方的非标准数据,建议在入口阶段就做格式校验和错误报告。