Json - stringify so that arrays are on one line
Is it possible to stringify a JSON object to look like this, with arrays in one line - not indented
{
"Repeat": {
"Name": [["Top_开发者_如何转开发level","All"],[[1,1]]],
"Link": [["Top_level"],[[1,1]]]
},
"Delete": ["Confirm","Cancel"],
"Move": ["Up","Down"],
"Number": ["Ascending","Descending"]
}
Try this:
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);
Result:
"{
"Repeat": {
"Name": "[[\"Top_level\",\"All\"],[[1,1]]]",
"Link": "[[\"Top_level\"],[[1,1]]]"
},
"Delete": "[\"Confirm\",\"Cancel\"]",
"Move": "[\"Up\",\"Down\"]",
"Number": "[\"Ascending\",\"Descending\"]"
}"
Taking the answers from ericbowden and bigp, I produced the below function which allows me to pretty print JSON while keeping an array on a single line and keeping the array in array form instead of converting it to a string.
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;
}
If you mean to display short arrays as single lines, consider using json-stringify-pretty-compact. It produces results looking as follows:
{
"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}
]
}
Another approach which I took:
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))
*Array must not contain strings (notice the " in the not contains inside the regex), if you remove it it will catch key,values of:
"[": "[1,2,3,4]",
Update 2020-03 - I worked out a more stable solution
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));
Another modern answer for an old question: Take a look at FracturedJson. That link will take you to the web version, but it's available as a commandline app, and libraries for .NET and JS.
FracturedJson will inline arrays/objects as long as they're neither too long nor too complex. It can likewise split arrays into multiple lines with multiple items per line.
Here's an example using the default settings, but you can adjust them to whatever works best for your data.
{
"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]
]
}
Disclosure: I'm the author of FracturedJson. It's open source under an MIT license.
Try this:
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, '"');
Mind you this uses lodash
to detect Arrays and Objects, here's another method that will keep the "leaf" objects compact on one line:
_.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,'}');
};
And just use it like this:
_.jsonPretty(yourObjectToStringify);
Here's an example before...
{
"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"
}
]
}
]
}
... and after:
{
"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"}
]
}
]
}
Here is a solution I worked out which may be useful as a basis for doing something similar:
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")
}
I could not figure out how to do replace as some members go down five levels,so I recreated the whole thing. The solution is not so hot but I got what I wanted to achieve - sample below:
"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"]
},
I use JSON format for my app's configuration files. They are quite dissimilar and big enough, so different formatting rules are required to make them look better and readable. Unfortunately, provided answers are not flexible enough so I've made my own implementation called perfect-json to beautify JSON.
Consider that you want to format object in the question like this:
{
"Repeat": {
"Name": [
["Top_level", "All"],
[[1, 1]]
],
"Link": [
["Top_level"],
[[1, 1]]
]
},
"Delete": ["Confirm", "Cancel"],
"Move": ["Up", "Down"],
"Number": [
"Ascending",
"Descending"
]
}
With perfect-json
it can be achieved:
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;
}
}));
It's also easy to place each array on a single line as asked in the question:
console.log(perfectJson(obj, {
indent: 4,
singleLine: ({ value }) => Array.isArray(value)
}));
I use prettier.
First install it:
npm i prettier
Then use it:
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" });
精彩评论