Json - stringify 使数组在一行上

28

是否可以将JSON对象字符串化为以下形式,其中数组在一行中 - 不缩进?

{
    "Repeat": {
        "Name": [["Top_level","All"],[[1,1]]],
        "Link": [["Top_level"],[[1,1]]]
    },
    "Delete": ["Confirm","Cancel"],
    "Move": ["Up","Down"],
    "Number": ["Ascending","Descending"]
}
10个回答

22

试试这个:

var obj = {"Repeat": {"Name":[["Top_level","All"],[[1,1]]],"Link": [["Top_level"],[[1,1]]]},"Delete": ["Confirm","Cancel"],"Move": ["Up","Down"],"Number": ["Ascending","Descending"]};

JSON.stringify(obj,function(k,v){
   if(v instanceof Array)
      return JSON.stringify(v);
   return v;
},2);

结果:

"{
  "Repeat": {
    "Name": "[[\"Top_level\",\"All\"],[[1,1]]]",
    "Link": "[[\"Top_level\"],[[1,1]]]"
  },
  "Delete": "[\"Confirm\",\"Cancel\"]",
  "Move": "[\"Up\",\"Down\"]",
  "Number": "[\"Ascending\",\"Descending\"]"
}"

谢谢,看起来更像应该的样子。我会适时尝试一下。k是什么意思? - Chris Glasier
k和v是传递给该函数的对象的键/值,这种情况下k没有任何作用。 - ericbowden
9
数组会以单个字符串的形式输出;是否有一种同样聪明的方法将它们返回为数组?如果有,你的答案肯定会被采纳。 - Chris Glasier
7
输出如下:"images": "[\"2\",\"3\",\"4\",\"5\",\"6\",\"7\"]" - Chris Glasier
1
这一部分有些棘手,我在实现它时所做的是使用正则表达式剥离引号和反斜杠。至于数组,你可以编写一个递归方法,每次检测到一个数组时循环并将其添加到输出字符串的末尾。从这里开始,可能会变得有点混乱。 - ericbowden
显示剩余2条评论

14
ericbowdenbigp 获取答案后,我编写了下面的函数,它使我能够漂亮地打印 JSON,同时将数组保持在单行并保持其为数组形式而不是将其转换为字符串。

function prettyPrintArray(json) {
  if (typeof json === 'string') {
    json = JSON.parse(json);
  }
  output = JSON.stringify(json, function(k,v) {
    if(v instanceof Array)
      return JSON.stringify(v);
    return v;
  }, 2).replace(/\\/g, '')
        .replace(/\"\[/g, '[')
        .replace(/\]\"/g,']')
        .replace(/\"\{/g, '{')
        .replace(/\}\"/g,'}');

  return output;
}

1
谢谢你的回答 - 这个很好用。我已经修改了你的函数以通过JSLint:const prettyPrintArray = obj => JSON.stringify( obj, (key, val) => (val instanceof Array) ? JSON.stringify(val) : val, 2).replace(/\\/g, '').replace(/\[/g, '[').replace(/\]/g,']').replace(/\{/g, '{').replace(/\}/g,'}'); - LukeT
如果您有一个以方括号或花括号结尾的字符串值,这将不会生成有效的JSON字符串,因为底部的替换调用将替换字符串的闭合引号。 - undefined

11

如果您希望将短数组显示为单行,请考虑使用json-stringify-pretty-compact。它产生的结果如下所示:

{
  "bool": true,
  "short array": [1, 2, 3],
  "long array": [
    {"x": 1, "y": 2},
    {"x": 2, "y": 1},
    {"x": 1, "y": 1},
    {"x": 2, "y": 2}
  ]
}

一旦你开始使用,这个工具还是挺好用的。不过安装过程有点奇怪,或者说我可能不太懂怎么操作... 通过npm安装很容易。之后,为了让它正常工作,你的脚本标签需要指向'index.js'(没有json-stringify-pretty-compact js文件)。然后你需要注释掉最后一行,像这样://module.exports = stringify。然后你就可以像这样使用它来代替JSON.stringify:stringify(jSONObject, null, 2)。确实,它让JSON看起来更美观。 - Travis Heeter

8

我采取的另一种方法:

obj => JSON.stringify(obj, (k,v) => Array.isArray(v) ? JSON.stringify(v) : v, 2)
.replace(/"\[[^"\]]*]"/g, r => JSON.stringify(JSON.parse(r)).substr(1).slice(0,-1))

*数组中不得包含字符串(请注意在正则表达式内部的not contains中的引号),如果您将其删除,它将捕获键值对:

"[": "[1,2,3,4]",

2020-03更新 - 我制定了一种更稳定的解决方案

const obj = {
  "first_name": "John",
  "last_name": "Smith",
  "age": 21,
  "hobbies": [ "programming", "workout", null, undefined, 24, "\"has double quotes\"" ],
  "nested": {
    "arr": [ "one", "two", "three" ],
  },
  "nested_arr": [
    "first as string",
    {
      "latin": [ "alpha", "beta", "[gamma]" ]
    },
    null
  ]
};

const stringify = (obj, indent = 2) => 
  JSON.stringify(obj, (key, value) => {
    if (Array.isArray(value) && !value.some(x => x && typeof x === 'object')) {
      return `\uE000${JSON.stringify(value.map(v => typeof v === 'string' ? v.replace(/"/g, '\uE001') : v))}\uE000`;
    }
    return value;
  }, indent).replace(/"\uE000([^\uE000]+)\uE000"/g, match => match.substr(2, match.length - 4).replace(/\\"/g, '"').replace(/\uE001/g, '\\\"'));

console.log(stringify(obj));


你认为会得到这个结果吗:www.glasier.hk - 选择JSON - Chris Glasier
对于一般的美化,我建议使用第三方库,正如@Piotr Migdal所建议的那样。 - EliSherer
substr方法自从被弃用以来,可以使用match.substring(2, match.length - 2)来代替。 - undefined

8

一个古老问题的现代答案:看看FracturedJson。该链接将带您前往Web版本,但它也可用作命令行应用程序和.NET和JS的库。

如果数组/对象既不太长也不太复杂,则FracturedJson会将它们内联。 同样,它可以将数组拆分为多行,并在每行中放置多个项。

这是一个使用默认设置的示例,但您可以根据数据选择最佳设置。

{
    "SimpleItem": 77,
    "ComplexObject": {
        "Subthing1": {"X": 55, "Y": 19, "Z": -4},
        "Subthing2": { "Q": null, "W": [-2, -1, 0, 1] },
        "Distraction": [[], null, null]
    },
    "ShortArray": ["blue", "blue", "orange", "gray"],
    "LongArray": [
        2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 
        79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 
        163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 
        251, 257, 263, 269, 271, 277, 281, 283, 293
    ],
    "LongArray2": [
        [19, 2],
        [3, 8],
        [14, 0],
        [9, 9],
        [9, 9],
        [0, 3],
        [10, 1],
        [9, 1],
        [9, 2],
        [6, 13],
        [18, 5],
        [4, 11],
        [12, 2]
    ]
}

声明:我是FracturedJson的作者。它是使用MIT许可证开源的。


我认为这是最好的解决方案。谢谢! - philo

4

试试这个:

JSON.stringify(obj,function(k,v){
   if(v instanceof Array)
      return JSON.stringify(v);
   return v;
},4)
.replace(/"\[/g, '[')
.replace(/\]"/g, ']')
.replace(/\\"/g, '"')
.replace(/""/g, '"');

1
我尝试过,但这在多层对象中不起作用。 - Chris Glasier

2

请注意,这里使用 lodash 来检测数组和对象,以下是另一种方法,可以将“叶子”对象压缩在一行中:

_.jsonPretty = function(obj, indent) {
    if(!indent) indent = 2;

    return JSON.stringify(obj, function(k,v) {
        //Check if this is a leaf-object with no child Arrays or Objects:
        for(var p in v) {
            if(_.isArray(v[p]) || _.isObject(v[p])) {
                return v;
            }
        }

        return JSON.stringify(v);

        //Cleanup the escaped strings mess the above generated:
    }, indent).replace(/\\/g, '')
        .replace(/\"\[/g, '[')
        .replace(/\]\"/g,']')
        .replace(/\"\{/g, '{')
        .replace(/\}\"/g,'}');
};

只需要像这样使用它:

_.jsonPretty(yourObjectToStringify);

以下是之前的例子...

{
  "type": "light-item",
  "name": "Waiting",
  "ringSeqLooping": true,
  "ringSeqHoldLast": false,
  "ringSteps": [
    {
      "type": "light-step",
      "time": 1,
      "audioClipName": "Off",
      "audioVolume": 1,
      "lights": [
        {
          "state": "FadeOn",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        }
      ]
    },
    {
      "type": "light-step",
      "time": "0.5",
      "audioClipName": "Off",
      "audioVolume": 1,
      "lights": [
        {
          "state": "FadeOff",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        }
      ]
    }
  ],
  "stripSeqLooping": true,
  "stripSeqHoldLast": false,
  "stripSteps": [
    {
      "type": "light-step",
      "time": "2",
      "audioClipName": "Off",
      "audioVolume": 1,
      "lights": [
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "FadeOn",
          "color": "#fff"
        },
        {
          "state": "FadeOn",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        }
      ]
    },
    {
      "type": "light-step",
      "time": "2",
      "audioClipName": "Off",
      "audioVolume": 1,
      "lights": [
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "FadeOff",
          "color": "#fff"
        },
        {
          "state": "FadeOff",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        },
        {
          "state": "Off",
          "color": "#fff"
        }
      ]
    }
  ]
}

……之前和之后

{
  "type": "light-item",
  "name": "Waiting",
  "ringSeqLooping": "true",
  "ringSeqHoldLast": "false",
  "ringSteps": [
    {
      "type": "light-step",
      "time": "1",
      "audioClipName": "Off",
      "audioVolume": "1",
      "lights": [
        {"state":"FadeOn","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"}
      ]
    },
    {
      "type": "light-step",
      "time": "0.5",
      "audioClipName": "Off",
      "audioVolume": "1",
      "lights": [
        {"state":"FadeOff","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"}
      ]
    }
  ],
  "stripSeqLooping": "true",
  "stripSeqHoldLast": "false",
  "stripSteps": [
    {
      "type": "light-step",
      "time": "2",
      "audioClipName": "Off",
      "audioVolume": "1",
      "lights": [
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"FadeOn","color":"#fff"},
        {"state":"FadeOn","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"}
      ]
    },
    {
      "type": "light-step",
      "time": "2",
      "audioClipName": "Off",
      "audioVolume": "1",
      "lights": [
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"FadeOff","color":"#fff"},
        {"state":"FadeOff","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"},
        {"state":"Off","color":"#fff"}
      ]
    }
  ]
}

唉...我刚刚注意到一些缺陷(特别是布尔值和数字),它会在其周围放置双引号。我想这取决于您是否决定在整个JSON字符串中进行更全局的替换以删除这些边缘情况。 - chamberlainpi

1

这里是我拟定的一个解决方案,可能对类似问题的解决提供一些有用的基础:

function labTab(ind){
    var tab,com,a;
    tab = "\t";
    com = [];
    for(a = 0; a < ind; a+=1){
        com.push(tab)
    }
    return com.join("");
}

function nsetEntry(tab,o,obj){
    return tab + '"'+ o + '":' + JSON.stringify(obj[o]);
}

function nsetObject(tab,o,obj,arr,ind){
    var start;
    start = tab + '"'+ o + '":{'; 
    return [start,nsetConstructor(obj[o],arr,ind)].join("\n") + "\n" + tab +"}"; 
}

function nsetConstructor(obj,arr,ind){
    var narr,tab,o,entry;
    narr = [];
    ind += 1;
    tab = labTab(ind);
    for(o in obj){
        if(obj[o].constructor === Object){
            entry = nsetObject(tab,o,obj,arr,ind);
            narr.push(entry); 
        }
        else{
            entry = nsetEntry(tab,o,obj);
            narr.push(entry);
        }
    }
    return narr.join(",\n");
}

function nsetLevels(obj,arr,ind){
    var o,start,tab;
    tab = labTab(ind);
    for(o in obj){
        if(obj[o].constructor === Object){
            entry = nsetObject(tab,o,obj,arr,ind);
            arr.push(entry); 
        }
        else{
            entry = nsetEntry(tab,o,obj);   
            arr.push(entry);
        }
    }
        return arr.join(",\n");
}

function nsetSave(){
    var json,o,ind,tab,obj,start,head,tail;
    json = [];
    for(o in nset){
        ind = 1;
        tab = labTab(ind);
        start = tab + '"'+ o + '":{';
        ind = 2;
        tab = labTab(ind);
        obj = nset[o];
        json.push([start,nsetLevels(obj,[],ind)].join("\n"))
    }
    head = "{\n";
    tail = "\n\t}\n}"
    FW.Write([head,json.join("\n\t},\n"),tail].join(""),"xset.json")
}

我无法弄清如何进行替换,因为有些成员下降了五个级别,所以我重新创建了整个内容。解决方案并不是很好,但我达到了想要实现的目标-以下是示例:

    "Key":{
        "Label":{
            "Change":["Input"],
            "Repeat":{
                "Name":[["Top_level","All"],[[1,1]]],
                "Link":[["Top_level"],[[1,1]]]
            },
            "Delete":["Confirm","Cancel"],
            "Move":["Up","Down"],
            "Number":["Ascending","Descending"]
        },
        "Class":{
            "Change":["Input"]
        },

1

我使用Prettier。

首先安装它:

npm i prettier

然后使用它:
const prettier = require("prettier")

const obj = {"Repeat": {"Name":[["Top_level","All"],[[1,1]]],"Link": [["Top_level"],[[1,1]]]},"Delete": ["Confirm","Cancel"],"Move": ["Up","Down"],"Number": ["Ascending","Descending"]};

const json = prettier.format(JSON.stringify(obj), { parser: "json" });

1
我使用JSON格式作为我的应用程序配置文件。它们非常不同且足够大,因此需要不同的格式规则使其看起来更好,更易读。不幸的是,提供的答案不够灵活,所以我自己实现了一个名为perfect-json的工具来美化JSON。
考虑您想要将问题中的对象格式化如下:
{
  "Repeat": {
    "Name": [
      ["Top_level", "All"],
      [[1, 1]]
    ],
    "Link": [
      ["Top_level"],
      [[1, 1]]
    ]
  },
  "Delete": ["Confirm", "Cancel"],
  "Move": ["Up", "Down"],
  "Number": [
    "Ascending",
    "Descending"
  ]
}

使用 perfect-json 可以实现此目标:
import perfectJson from 'perfect-json';

const obj = {
  Repeat: {
    Name: [['Top_level', 'All'], [[1, 1]]],
    Link: [['Top_level'], [[1, 1]]]
  },
  Delete: ['Confirm', 'Cancel'],
  Move: ['Up', 'Down'],
  Number: ['Ascending', 'Descending']
};

console.log(perfectJson(obj, {
  singleLine: ({ key, path, depth }) => {
    if (['Delete', 'Move'].includes(key)) {
      return true;
    }
    if (depth >= 3 && ['Name', 'Link'].includes(path[1])) {
      return true;
    }
    return false;
  }
}));

根据问题的要求,将每个数组放在单独一行也很容易实现:

console.log(perfectJson(obj, {
  indent: 4,
  singleLine: ({ value }) => Array.isArray(value)
}));

1
正好赶上这个问题十周年。给我一些时间来消化它;我相信它值得一个点赞。 - Chris Glasier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接