簡體   English   中英

JSON.stringify 自定義格式

[英]JSON.stringify custom formatting

我正在尋找一種將 JSON 對象寫入文件的方法,但保持與原始格式相同的格式。 我已經設法使用 writeFileSync(path,data) 和 JSON.stringify() 編寫了內容,但正在努力弄清楚如何自定義格式。 JSON.stringify 接受的選項似乎只格式化空格數。

有什么方法可以使用 JSON.stringify 生成以下格式

{
  "key1"           :{"key": "value1","key": "value2"},
  "key2"           :{"key": "value1","key": "value2"}
}

而不是默認生成的

{
  "key1": 
   {
     "key": "value1",
     "key": "value2"
   },
  "key2": 
   {
     "key": "value1",
     "key": "value2"
   },
}

不幸的是,您可以使用space 參數來定義落入樹中的對象的間距。 您提議的內容需要使用諸如正則表達式之類的自定義格式來格式化字符串。

但是,您會在下面找到一些示例代碼來執行您想要執行的操作。 可以將所有這些附加到單個命令中,例如JSON.stringify(myJSON, null, ' ').replace(/: \\{\\n\\s+/g, ': {').replace(/",\\n\\s+/g, ', ').replace(/"\\n\\s+\\}/g, '}'); ,但是為了讓你看到我做了什么,我一步一步地分解了它。

 const myJSON = { "key1":{"key": "value1","key2": "value2"}, "key2":{"key": "value1","key2": "value2"} } let myString = JSON.stringify(myJSON, null, ' ').replace(/: {/g, `${' '.repeat(5)}: \\{`); //Set the key spacing myString = myString.replace(/: \\{\\n\\s+/g, ': {'); //Bring the child bracket on the same line myString = myString.replace(/",\\n\\s+/g, ', '); //Bring all the other objects for that array up myString = myString.replace(/"\\n\\s+\\}/g, '}'); //Pull the closing bracket on the same line const myCompactString = JSON.stringify(myJSON, null, ' ').replace(/: {/g, `${' '.repeat(5)}: \\{`).replace(/: \\{\\n\\s+/g, ': {').replace(/",\\n\\s+/g, ', ').replace(/"\\n\\s+\\}/g, '}'); //Done all at once console.log(`myString: ${myString}`); console.log(`myCompactString: ${myCompactString}`);

我想要這樣的格式:

var house = {
    family: {
        surname: "Smith",
        people: 4,
        pets: {
            dogs: {number:1, names:["toby"]},
            cats: {number:2, names:["bob", "boo"]},
            platypus: {number:1, names:["perry"], codename: ["agent p"]},
        }
    },
    livingRoom: [
        {name:"couch", amount:2},
        {name:"shelf", amount:1},
        {name:"nightstand", amount:1},
        {name:"television", amount:1},
    ],
    bedroom: [
        {name:"bed", amount:1},
        {name:"wardrobe", amount:1},
        {name:"shelf", amount:2},
    ],
}

這是一個類似的問題,但是在更復雜的對象樹中具有更具體的對象鍵,並且僅使用正則表達式就開始變得非常復雜。 因此,我使用toJSONstringify替換器創建了一個函數作為處理此問題的工具。

我創建的函數有一些限制,例如只能定義 singleLine 和 multiLine 對象,而不是數字或文本列表。 它還具有用於替換方案的某些特定字符的限制,它們是不常見的字符,但請查看是否必須替換它們。 字符有四個:'╲'(假\\)、'”'(​​假“)、'→'和'←',如果你的對象包含它們中的任何一個,你可以在函數的最開始替換它們。

這是一個函數工作的例子:

 const customStringify = function (obj, replacer, space = "\\t", { singlelineObjectKeys = [], multilineObjectKeys = [], singlelineChildKeys = [], multilineChildKeys = [], singlelineInsideList = [] }) { // WARNING // - This function will make a mess if your Object contain some of the following characters: const fakeReverseSlash = "╲"; // (fake \\) const fakeQuote = "”"; // (fake ") const startString = "→"; const endString = "←"; // So a solution in this case can be replace this chars by others not used (dont use characters that can mess the regex) // First make a stringify to solve any toJSON in the main object, then copy the main object stringfied to create all the necessary new toJSON let objModified = JSON.parse(JSON.stringify(obj, replacer)); // Convert an entire object to single line string const singleLineOBJ = function () { let obj = { ...this }; // To not change any toJSON delete obj.toJSON // To not fall in a stringify loop // Mark the startString and endString return startString + ( JSON.stringify(obj) // Replace all " by fakeQuote .replace(/"/g, fakeQuote) ) + endString; } // Convert an entire object to multi line string const multiLineOBJ = function () { let obj = { ...this }; // To not change any toJSON delete obj.toJSON // To not fall in a stringify loop // Mark the startString and endString return startString + ( JSON.stringify(obj, null, '\\t') // Replace all " by fakeQuote .replace(/"/g, fakeQuote) // Replace \\n using fakeReverseSlash .replace(/\\n/g, fakeReverseSlash + "n") // Replace \\t using fakeReverseSlash .replace(/\\t/g, fakeReverseSlash + "t") ) + endString; } // Checks all keys on the object const throughEveryKey = function (key, value) { let obj = this; // objects with some key to become single-line if (singlelineObjectKeys.includes(key)) { obj[key].toJSON = singleLineOBJ; } // objects with some key to become multi-line if (multilineObjectKeys.includes(key)) { obj[key].toJSON = multiLineOBJ; } // objects containing the following keys to become single-line if (singlelineChildKeys.includes(key)) { obj.toJSON = singleLineOBJ; } // objects containing the following keys to become multi-line if (multilineChildKeys.includes(key)) { obj.toJSON = multiLineOBJ; } // names of list of objects to each list-item become single-line if (singlelineInsideList.includes(key)) { obj[key].forEach((objectInsideList) => objectInsideList.toJSON = singleLineOBJ) } return value; } // Just use stringify to go through all object keys, and apply the function to implement "toJSON" in right places, the result of stringify is not used in this case JSON.stringify(objModified, throughEveryKey); // Use stringfy with right replacers, end result return JSON.stringify(objModified, null, '\\t') // Put in all start of line the right number of Tabs .replace(new RegExp('(?:(?<=(?<leadTab>^\\t*).+?)(?<newLine>' + fakeReverseSlash + 'n)(?=.+?))+', 'gm'), "$&$1") // Replace the fake tab by the real one .replace(new RegExp(fakeReverseSlash + 't', 'gm'), "\\t") // Replace the fake new line by the real one .replace(new RegExp(fakeReverseSlash + 'n', 'gm'), "\\n") // Replace the fake quote by the real one .replace(new RegExp(fakeQuote, 'gm'), '"') // Remove start and end of line from the stringfied object .replace(new RegExp('"' + startString, 'gm'), "") .replace(new RegExp(endString + '"', 'gm'), "") // Replace tab by custom space .replace(/(?<=^\\t*)\\t/gm, space); } var house = { family: { surname: "Smith", people: 4, pets: { dogs: {number:1, names:["toby"]}, cats: {number:2, names:["bob", "boo"]}, platypus: {number:1, names:["perry"], codename: ["agent p"]}, } }, livingRoom: [ {name:"couch", amount:2}, {name:"shelf", amount:1}, {name:"nightstand", amount:1}, {name:"television", amount:1}, ], bedroom: [ {name:"bed", amount:1}, {name:"wardrobe", amount:1}, {name:"shelf", amount:2}, ], } console.log("A custom stringify:\\n\\n"); console.log( customStringify(house, null, '\\t', { singlelineObjectKeys: ["dogs","cats","platypus"], multilineObjectKeys: ["family"], multilineChildKeys: [], singlelineChildKeys: [], singlelineInsideList: ["livingRoom","bedroom"], }) ); console.log("\\n\\n\\n"); console.log("A normal stringify:\\n\\n"); console.log(JSON.stringify(house, null, '\\t'));

您需要傳遞一些信息才能工作,您不需要使用所有內容,但我將解釋我准備在 multiLine 和 singleLine 之間格式化的情況:

singlelineObjectKeys:將需要在一行上的對象的鍵放在這里

multilineObjectKeys:將需要格式化的對象的keys放在多行

multilineChildKeys:如果您不想指定父對象,因為它們可以有很多,請為要在多行上格式化的父對象指定一個子鍵

singlelineChildKeys:如果您不想指定父對象,因為它們可以有很多,請在一行中為要格式化的父對象指定一個子鍵

singlelineInsideList:如果您有一個對象列表,並且您希望該列表中的所有對象都被格式化為一個列表,請在此處輸入該列表的鍵

在上面的例子中,使用的代碼是這樣的:

customStringify(house, null, '\t', {
    singlelineObjectKeys: ["dogs","cats","platypus"],
    multilineObjectKeys: ["family"],
    singlelineInsideList: ["livingRoom","bedroom"],
})

但這將導致相同的結果,例如:

customStringify(house, null, '\t', {
    singlelineChildKeys: ["name","names"],
})

由於我在幾個地方對此進行了研究,但一無所獲,因此我在此處注冊了我的解決方案(這是我尋找的地方之一)。 放心使用!

以 KevynTD 的出色回答為基礎!

保持字符串數組 ['song', 'bird'] 從更改為 {'0': 'song', '1': 'bird'} 索引鍵控對象。 添加if (Array.isArray(this)) obj = this; 到 singleLineOBJ 函數。

    const singleLineOBJ = function () {
        let obj = { ...this }; // To not change any toJSON
        if (Array.isArray(this))
            obj = this; // override converting array into object

        delete obj.toJSON // To not fall in a stringify loop

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM