提问人:axkibe 提问时间:3/10/2012 最后编辑:Boannaxkibe 更新时间:5/6/2023 访问量:41847
解析“宽松”的 JSON,而不使用 eval
Parsing "relaxed" JSON without eval
问:
解析“宽松”JSON但避免邪恶的最简单方法是什么?eval
以下代码会引发错误:
JSON.parse("{muh: 2}");
因为正确的 JSON 应该有引号的键:{"muh": 2}
我的用例是一个简单的测试接口,我用它来将 JSON 命令编写到我的节点服务器。到目前为止,我只是使用它,因为它只是一个测试应用程序。但是,在整个项目中使用 JSHint 一直困扰着我。因此,我想要一个安全的替代方案,它仍然允许宽松的键语法。eval
eval
PS:我不想为了测试应用程序而自己编写解析器:-)
答:
如果在编写字符串时不能引用键,则可以在使用 JSON.parse- 之前插入引号
var s= "{muh: 2,mah:3,moh:4}";
s= s.replace(/([a-z][^:]*)(?=\s*:)/g, '"$1"');
var o= JSON.parse(s);
/* returned value:[object Object] */
JSON.stringify(o)
/* returned value: (String){
"muh":2, "mah":3, "moh":4
}
评论
"{muh: true, notMuch: 123, pika:{pika:\"chu\"}}"
{"muh": "true, notMuch": 123, "pika":{"pika":"chu"}}
s= s.replace(/([a-z][^:]*)(?=\s*:)/gi, '"$1"');
你已经知道这一点,因为你把我带到了这里,但我认为在这里记录下来可能会很好:
长期以来,我一直渴望能够编写仍然有效的 JS 的“宽松”JSON,所以我采用了 Douglas Crockford 的免评估json_parse.js,并将其扩展为支持 ES5 功能:
https://github.com/aseemk/json5
此模块在 npm 上可用,可用作本机方法的直接替代品。(其输出为常规 JSON。JSON.parse()
stringify()
希望这有帮助!
评论
您可以使用正则表达式 replace 来清理 JSON:
var badJson = "{muh: 2}";
var correctJson = badJson.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": ');
JSON.parse(correctJson);
评论
value
\s*
:/g
{muh : 2}
{muh: "2:30pm"}
:
这就是我最终不得不做的。我扩展了@ArnaudWeil的答案,并添加了对出现在值中的支持::
var badJSON = '{one : "1:1", two : { three: \'3:3\' }}';
var fixedJSON = badJSON
// Replace ":" with "@colon@" if it's between double-quotes
.replace(/:\s*"([^"]*)"/g, function(match, p1) {
return ': "' + p1.replace(/:/g, '@colon@') + '"';
})
// Replace ":" with "@colon@" if it's between single-quotes
.replace(/:\s*'([^']*)'/g, function(match, p1) {
return ': "' + p1.replace(/:/g, '@colon@') + '"';
})
// Add double-quotes around any tokens before the remaining ":"
.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?\s*:/g, '"$2": ')
// Turn "@colon@" back into ":"
.replace(/@colon@/g, ':')
;
console.log('Before: ' + badJSON);
console.log('After: ' + fixedJSON);
console.log(JSON.parse(fixedJSON));
它产生以下输出:
Before: {one : "1:1", two : { three: '3:3' }}
After: {"one": "1:1", "two": { "three": "3:3" }}
{
"one": "1:1",
"two": {
"three": "3:3"
}
}
评论
您还可以使用 Flamenco 的 really-relaxed-json (https://www.npmjs.com/package/really-relaxed-json),它更进一步,不允许使用逗号、悬空逗号、注释、多行字符串等。
这是规范 http://www.relaxedjson.org
还有一些在线解析器:
http://www.relaxedjson.org/docs/converter.html
预加载了“bad json”
{one : "1:1", two : { three: '3:3' }}
预装了“更糟糕的 json”(没有逗号)
{one : '1:1' two : { three: '3:3' }}
预加载了“可怕的 json”(没有逗号、没有引号和转义冒号)
{one : 1\:1 two : {three : 3\:3}}
评论
[编辑:此解决方案仅适用于非常简单的对象和数组,但不适用于嵌套对象等更复杂的场景。我建议使用像jsonrepair这样的东西来处理更有趣的情况。
我稍微修改了 Arnaud 的解决方案,以处理键中的句点、键值中的冒号和任意空格(尽管它不处理 JSON 对象键值):
var badJson = `{
firstKey: "http://fdskljflksf",
second.Key: true, thirdKey:
5, fourthKey: "hello"
}`;
/*
\s*
any amount of whitespace
(['"])?
group 1: optional quotation
([a-z0-9A-Z_\.]+)
group 2: at least one value key character
(['"])?
group 3: optional quotation
\s*
any amount of whitespace
:
a colon literal
([^,\}]+)
group 4: at least one character of the key value (strings assumed to be quoted), ends on the following comma or closing brace
(,)?
group 5: optional comma
*/
var correctJson = badJson.replace(/\s*(['"])?([a-z0-9A-Z_\.]+)(['"])?\s*:([^,\}]+)(,)?/g, '"$2": $4$5');
JSON.parse(correctJson);
评论
test { _item123456: { data { type: "Object", id: "XY12246", date: "2018-04-12 16:19:42", shape: "cube", state: "painted" } } }
如果您正在编写 NodeJS 代码,您还可以使用该模块来创建比解析宽松 JSON 更安全的环境。虽然环境可以运行任意代码,但会更严密,它是一个纯 V8 沙箱,没有 or 之类的东西。node:vm
eval
vm
require
process
const vm = require('vm'); // or node:vm
const badJson = '{muh: 2}';
try {
const parsedJson = new vm.Script(`x=${badJson}`).runInNewContext(
{ console: undefined }, // nuke console inside the vm
{ timeout: 1000, displayErrors: true }
);
if (typeof parsedJson !== 'object') { // in case you're expecting an object/array
throw new Error(`Invalid JSON=${badJson}, parsed as: ${parsedJson}`);
}
console.log(parsedJson);
} catch (err) {
throw new Error(`Could not parse JSON: ${err}`);
}
您可以改用一个模块,该模块承诺更高的安全性并执行相同的操作:https://github.com/patriksimek/vm2vm2
评论
这是我的简单解决方案,适用于值中的嵌套对象和分号:
const finalJson = relaxedJson
.replace(/([{,])\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*:/g, "$1\"$2\":");
评论
eval
JSON.parse