Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a simple way to customize how arrays are formatted by JSON.stringify?

I often want to "pretty print" (include extra white-space to make it easier for humans to interpret) JavaScript objects, and JSON.stringify(myObject, null, " ") usually suffices for this. However, in many cases, there are arrays of numbers that I really don't want split onto new lines.

Is there a simple/elegant way of accomplishing this with the native JSON.stringify function?

I tried using a "replacer" function but this seems to only facilitate alteration (e.g. modify data), filtering (e.g. omit data), and side-effects (e.g. log data) -- see also How Do I Use The Replacer Function With JSON Stringify?.

Alternatively, is there an established module/library/utility for doing this already or should I write my own?

There appear to be many search results on npm.org for "stringify", but the ones I saw seem to just be variations that either run more efficiently on a particular problem domain or avoid problems related to circular/cyclic data structures.

const obj = {
  foo: "bar",
  oneLine: [1,2,3],
  multipleLines: [{
    name: "X",
    alsoOneLine: [4,5,6]
  }, {
    name: "Y"
  }]
};

document.write(`
  <pre>
    // This isn't the output I want. 
    // The arrays containing only numbers should have their elements
    // all printed on the same line.
    ${JSON.stringify(obj, null, "  ")}
  </pre>
`);
like image 922
jacobq Avatar asked Jan 23 '26 18:01

jacobq


1 Answers

You can use a regular expression to search the stringified version for arrays of numbers, and replace the whitespaces in all those those arrays-of-numbers with the empty string. By anchoring the beginning of the pattern to the beginning of a line with ^, you can ensure that the matched key-value pair (or plain value, in the case the array of numbers is contained in another array) is an array, and not something else, like a string that contains something that looks like a JSON-array-of-numbers:

const obj = {
  foo: "bar",
  oneLine: [1, 2, 3],
  multipleLines: [{
    name: "X",
    alsoOneLine: [4, 5, 6],
    inner: [
      [1, 2, 3],
      [4, 5, 6]
    ]
  }, {
    name: "Y"
  }]
};

const stringified = JSON.stringify(obj, null, "  ");
const numArraysOnOneLine = stringified.replace(
  /^( *)("[^"]+": )?(\[(?:\s+\d+,)*\s+\d+\s+\])/gm,
  (_, leadingWhitespace, possibleKeyStr='', arrStr) => (
    leadingWhitespace + possibleKeyStr + arrStr.replace(/\s+/g, ''
  ))
);
document.write(`<pre>${numArraysOnOneLine}</pre>`);

https://regex101.com/r/XfuqoT/1

The pattern

^( *)("[^"]+": )?(\[(?:\s+\d+,)*\s+\d+\s+\])

means:

  • ^ - Match the start of a line
  • ( *) First capturing group: capture the leading whitespace
  • ("[^"]+": )? Second group, optional: match the double-quoted key, if the array is contained in an object
  • \[ - Beginning of the third group. Match a literal [
  • (?:\s+\d+,)* - Repeat a group of whitespace characters followed by digits zero or more times
  • \s+\d+\s+ - Match the final item in the array (has no trailing comma): whitespace, followed by a digit, followed by more whitespace
  • \] - followed by the terminating ] (end of the third group)

If the numbers may contain decimals as well, then replace \d+ with \d+(?:\.\d+)? to allow for optional decimal digits.

If the object properties may contain double-quotes as well (escaped by backslash when stringified), then replace [^"]+ with (?:[^"]|\\")+ https://regex101.com/r/XfuqoT/2

like image 192
CertainPerformance Avatar answered Jan 25 '26 08:01

CertainPerformance



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!