Stringify 没有属性引号?

我使用的服务使用了不正确的 JSON 格式(属性周围没有双引号)

{ name: "John Smith" }而不是 { "name": "John Smith" }

这种格式不能改变,因为这不是我的服务。

有谁知道像上面这样格式化 JavaScript 对象的 stringify 路由吗?

144093 次浏览

这个简单的正则表达式解决方案可以在大多数情况下取消引用 JSON 属性名:

const object = { name: 'John Smith' };
const json = JSON.stringify(object);  // {"name":"John Smith"}
console.log(json);
const unquoted = json.replace(/"([^"]+)":/g, '$1:');
console.log(unquoted);  // {name:"John Smith"}

极端情况:

var json = '{ "name": "J\\":ohn Smith" }'
json.replace(/\\"/g,"\uFFFF");  // U+ FFFF
json = json.replace(/"([^"]+)":/g, '$1:').replace(/\uFFFF/g, '\\\"');
// '{ name: "J\":ohn Smith" }'

特别感谢 Rob W 修好了它。

限制

在正常情况下,前面提到的 regexp 可以工作,但是从数学上来说,不可能用正则表达式描述 JSON 格式,以便在每一种情况下都可以工作(对于 regexp,计算相同数量的花括号是不可能的)因此,我创建了一个新函数来删除引号,方法是通过本机函数正式解析 JSON 字符串并重新序列化它:

function stringify(obj_from_json) {
if (typeof obj_from_json !== "object" || Array.isArray(obj_from_json)){
// not an object, stringify using native function
return JSON.stringify(obj_from_json);
}
// Implements recursive object serialization according to JSON spec
// but without quotes around the keys.
let props = Object
.keys(obj_from_json)
.map(key => `${key}:${stringify(obj_from_json[key])}`)
.join(",");
return `{${props}}`;
}

例子: https://jsfiddle.net/DerekL/mssybp3k/

您可以查看 json2.js 由定义 JSON 格式的人创建的解析器的源代码。查找 quote函数调用: 这些函数调用用引号围绕值。键被引用在 326338行。

修改后不包括库。取而代之的是相关的(stringify)部分,或者至少用其他东西代替 JSON,例如。FAKEJSON.

例如,一个只定义了 stringify: http://jsfiddle.net/PYudw/的对象 FAKEJSON

尝试使用 JSONP 服务,我猜他们提供的时候使用这种格式。

否则,向他们提交一份详细的 bug 报告,其中包括为什么应该符合标准的充分论证。除了消除源问题之外的任何其他解决方案都不是真正的解决方案。

一个快速的 n 脏修复方法可能是在解析字符串之前通过正则表达式管道传输该字符串:

var obj = JSON.parse(str.replace(/(\{|,)\s*(.+?)\s*:/g, '$1 "$2":'));

或者,如果需要更多的语法解析,可以尝试调整现有的 javascript JSON 解析器(如 这个)。

您继承的语法应该很容易被 YAML 所接受,YAML 是 JSON 的超集。

尝试 JavaScriptYAML 解析器和 dump: http://nodeca.github.com/js-yaml/

看起来这就是您正在寻找的一个简单的 ObjecttoString 方法。

在 Node.js 中,可以通过使用 util 对象并调用 util.check (yourObject)来解决这个问题。这会给你想要的一切。点击这个链接查看更多选项,包括深度应用方法。http://nodejs.org/api/util.html#util_util_inspect_object_options

因此,您要寻找的基本上是一个对象检查器,而不是一个 JSON 转换器。JSON 格式指定所有属性必须用双引号括起来。因此,不会有 JSON 转换器来完成您想要的任务,因为它根本不是 JSON 格式。参数: Https://developer.mozilla.org/en-us/docs/using_native_json

对象进行字符串或检查取决于服务器的语言。

CSVJSON 的 JSON Beautifier 有一个在键上删除引号的选项。如果只想要代码,可以从 GitHub 回购中复制它。我 修改过的道格拉斯·克罗克福特的 JSON2添加支持。

找到了一个很好的 NPM 软件包来实现以下功能:

Https://www.npmjs.com/package/stringify-object

const stringify = require('stringify-object')


let prettyOutput = stringify(json);

效果很好。

@ Derek 朕会功夫感谢分享这个方法,我想分享我的代码,它也支持将一系列对象串联起来。

export const stringifyObjectWithNoQuotesOnKeys = (obj_from_json) => {
// In case of an array we'll stringify all objects.
if (Array.isArray(obj_from_json)) {
return `[${
obj_from_json
.map(obj => `${stringifyObjectWithNoQuotesOnKeys(obj)}`)
.join(",")
}]` ;
}
// not an object, stringify using native function
if(typeof obj_from_json !== "object" || obj_from_json instanceof Date || obj_from_json === null){
return JSON.stringify(obj_from_json);
}
// Implements recursive object serialization according to JSON spec
// but without quotes around the keys.
return `{${
Object
.keys(obj_from_json)
.map(key => `${key}:${stringifyObjectWithNoQuotesOnKeys(obj_from_json[key])}`)
.join(",")
}}`;
};

使用 JSON5.stringify

JSON5 是 JSON 的超集,它允许 ES5语法,包括 未被引用属性键。JSON5引用实现(json5 npm 包)提供了一个 JSON5对象,该对象具有与内置 JSON对象相同的具有相同参数和语义的方法。

您正在使用的服务很可能正在使用此库。

代码

关于浏览器的后台支持,下面有一个警告:

function cleanIt(obj) {
var cleaned = JSON.stringify(obj, null, 2);


return cleaned.replace(/^[\t ]*"[^:\n\r]+(?<!\\)":/gm, function (match) {
return match.replace(/"/g, "");
});
}

注意: 在 IE 或者奇怪的是,截至2021年6月18日的 Safari 任何版本上不支持后视。要在那里使用,从正则表达式中删除 (?<!\\),并注意下面提到的“ Gotcha”条件。

这种方法很漂亮,使用正则表达式查找键,然后通过 replacer function替换每个键匹配,该 replacer function表示“这是删除了所有双引号的匹配”。因为我们只把钥匙和他们的冒号对上了,这正是我们想要的。

详细描述如下。


为什么接受的答案是不对的

不幸的是,正如 阿黛尔指出指出的,Derek 的正则无表达式解决方案有一个非常严重的问题。它不处理对象数组.你看到它短路了,然后说,“如果它是一个数组,让 JSON.stringify处理它”?这对于简单的值类型是可以的,但对于对象就不行了。

//                                        \/\/\/ OH NOES!!! \/\/\/
if (typeof obj_from_json !== "object" || Array.isArray(obj_from_json)){
// not an object, stringify using native function
    

return JSON.stringify(obj_from_json);
//         ^^^^^^^^^^^^^^ No! Don't do that!
}

我编辑了他的 摆弄失败的案例这是有效载荷:

var obj = {
name: "John Smith",
favoriteObjects: [
{ b: "there's", c: "always", d: "something" },
[1, 2, "spam", { f: "hello" }],
{ vowels: "are missing" },
],
favoriteFruits: ["Apple", "Banana"],
};

这是空白的输出:

{
name:"John Smith",
favoriteObjects:[
{
"b":"there's",    <<< Major
"c":"always",     <<< fails
"d":"something"   <<< here
},
[
1,2,"spam",
{
"f":"hello"     <<< and here.
}
],
{
"vowels":"are missing" <<< again.
}
],
favoriteFruits:["Apple","Banana"] <<< that worked!
}

看到没?虽然字符串数组(favoriteFruits)可以工作,但是在序列化的第二级对象(如 favoriteObjects)中仍然有引号。很糟糕。


一个简单的解决办法

我花了太多的时间试图清理这个函数,然后才想出一个巧妙的技巧来大大降低问题的复杂性,我认为这又把正则表达式带回了混合中。

让我们使用带空格的 stringify

麦奎尔先生的血管中,我只想对你们说一个词,就一个词:

空格。

让我们使用一些空格的 JSON.stringify。这使得正则表达式从键中删除引号变得更加容易。

你的解决方案是这样开始的:

var cleaned = JSON.stringify(x, null, 2);

stringify的调用说“ stringify x(第一个参数)没有花哨的替代函数(由 null的第二个参数表示) ,在序列化的每个深度中有两个(2的第三个参数)空格。”那个 2也给我们每个房产买了单独的线路。

{
"name": "John Smith",
"favoriteObjects": [
{
"b": "there's",
"c": "always",
// etc...

现在每个键都很好地位于一行的开头。 那个我们可以处理。


NOW 清除键上的引号

让我们创建一个正则表达式来查找键,并且只查找键,然后取出它们周围的 "。因为我们知道现在所有的键都在它们自己的行上,所以事情变得更简单了。

唯一真正的问题是,如果一个属性的值中途包含 ":,那可能会把事情搞砸。

"a": [
"This could \": be bad",
"QQ"
]

看看后面的警告

我想用 老式浏览器的负面预测来解决这个问题,但是放弃了,使用了一个负向回望。在2018年之后,只有一部分浏览器支持负向查看(历史回顾提案在2ality 在这里描述,浏览器兼容性可以是 在这里发现的)。


正则表达式解释:

/^[\t ]*"[^:\n\r]+(?<!\\)":/gm

那个正则表达式。

  • 是正则表达式
    • /开始
  • 查找以(0到无穷大的空格或制表符)开始的任何行
    • ^[\t ]*
  • 然后是 "
    • "
  • 然后是 什么都行的一个或多个字符,即 不是:或换行符
    • [^:\n\r]+
  • 然后以(负面回顾警告) < em > 前面没有反斜杠的两个字符 ":结束
  • 这是否全局和多行(逐行)
    • /gm

合理成功的小提琴。

结果:

{
name: "John Smith",
favoriteObjects: [
{
b: "there's",
c: "always",
d: "something"
},
[
1,
2,
"spam",
{
f: "hello"
}
],
{
vowels: "are missing"
}
],
favoriteFruits: [
"Apple",
"Banana"
]
}

在 Jadent 提出这个问题短短的八年半之后,QED 出现了,这就是服务!


快速更新: 一个更好的答案,如果你不一定需要在代码中发生这种情况(尽管在某些用例中,你也可以直接调用这个库) ,可以是使用 更漂亮,它可以漂亮地清理东西。

就这么简单

.replace(/[\[\]']+/g, '')

这将取代:

什么都没有

或者

.replace(/[\{\}']+/g, '').

这将取代:

什么都没有

如果您希望导出 JSON 的方式能够直接在 JavaScript 代码中使用,那么下面的解决方案就是您想要的。这个解决方案适用于任何 JavaScript 变量,也适用于包含对象/数组的对象/数组。

下面函数的最佳用例是当您有 JSON 时,您希望在 JavaScript 中包含它,而不需要使用不必要的引号。这可以为您节省大量数据,特别是当您使用像“ x”和“ y”这样的短键时。

function toUnquotedJSON(param){ // Implemented by Frostbolt Games 2022
if(Array.isArray(param)){ // In case of an array, recursively call our function on each element.
let results = [];
for(let elem of param){
results.push(toUnquotedJSON(elem));
}
return "[" + results.join(",") + "]";
}
else if(typeof param === "object"){ // In case of an object, loop over its keys and only add quotes around keys that aren't valid JavaScript variable names. Recursively call our function on each value.
let props = Object
.keys(param)
.map(function(key){
// A valid JavaScript variable name starts with a dollar sign (?), underscore (_) or letter (a-zA-Z), followed by zero or more dollar signs, underscores or alphanumeric (a-zA-Z\d) characters.
if(key.match(/^[a-zA-Z_$][a-zA-Z\d_$]*$/) === null) // If the key isn't a valid JavaScript variable name, we need to add quotes.
return `"${key}":${toUnquotedJSON(param[key])}`;
else
return `${key}:${toUnquotedJSON(param[key])}`;
})
.join(",");
return `{${props}}`;
}
else{ // For every other value, simply use the native JSON.stringify() function.
return JSON.stringify(param);
}
}

我的解决方案使用函数构造函数创建一个临时函数,它将字符串解析为 JSON,然后将其字符串化:

function stringify2(notQuiteJsonString) {
var tempFunc = new Function(`return JSON.stringify(${notQuiteJsonString})`)
return tempFunc()
}


var jObj = `{a: 123, b: "This is b", c: {d: 10, c: "More stuff"}}`;
console.log(stringify2(jObj));
// {"a":123,"b":"This is b","c":{"d":10,"c":"More stuff"}}

尝试使用 bash/shell 和 nodejs 命令,似乎可以工作。

node <<END
> aaa = {
>   "abc": "xyz",
>   "num1": 1,
>   "text1": "my text",
>   "final": "the \"final\" text"
> }
> console.log(aaa)
> END
{ abc: 'xyz', num1: 1, text1: 'my text', final: 'the "final" text' }

如果取消引用 json 的目的是将数据保存到 mysql,那么可以使用 CAST(JSON_UNQUOTE(?) AS JSON))