12
\$\begingroup\$

Jason has a big JSON but it's unreadable, so he needs to prettify it.

Formatting Spec

The JSON has 4 different types:

  • Numbers; Just 0-9
  • Strings; Double quoted " strings escaped with \
  • Arrays; Delimited by [], with items separated by ,, items can be any of these types
  • Objects; Delimited by {}, format is key: value where key is a string and value is any of these types

Spacing

  • Arrays should have exactly one space after the commas between items
  • Objects should have have just one space between the key and the value, after the :

Indentation

  • Each nesting level is indented 2 more than the previous
  • Each object key/value pair is always on its own line. Objects are indented
  • An array is indented across multiple lines if it contains another array or object. Otherwise the array remains on one line

Rules

  • Built-ins which trivialize this task are not allowed.
  • As always standard loopholes are disallowed

Examples

[1,2,3]
[1, 2, 3]
{"a":1,"b":4}
{
  "a": 1,
  "b": 4
}
"foo"
"foo"
56
56
{"a":[{"b":1,"c":"foo"},{"d":[2,3,4,1], "a":["abc","def",{"d":{"f":[3,4]}}]}]}
{
  "a": [
    {
      "b": 1,
      "c": "foo"
    },
    {
      "d": [2, 3, 4, 1],
      "a": [
        "abc",
        "def",
        {
          "d": {
            "f": [3, 4]
          }
        }
      ]
    }
  ]
}
[2,["foo123 ' bar \" baz\\", [1,2,3]]]
[
  2,
  [
    "foo123 ' bar \" baz\\",
    [1, 2, 3]
  ]
]
[1,2,3,"4[4,5]"]
[1, 2, 3, "4[4,5]"]
[1,2,3,{"b":["{\"c\":[2,5,6]}",4,5]}]
[
  1,
  2,
  3,
  {
    "b": ["{\"c\":[2,5,6]}", 4, 5]
  }
]
\$\endgroup\$
8
  • 2
    \$\begingroup\$ Are JSON parsing builtins allowed? \$\endgroup\$ Commented Mar 1, 2016 at 7:45
  • \$\begingroup\$ Can objects/arrays be empty? Can we still print a space after commas in arrays if they split over multiple lines? \$\endgroup\$ Commented Mar 1, 2016 at 8:40
  • \$\begingroup\$ @MartinBüttner no, and yes \$\endgroup\$
    – Downgoat
    Commented Mar 1, 2016 at 14:59
  • \$\begingroup\$ @Pietu1998 hm, I'm going to say no \$\endgroup\$
    – Downgoat
    Commented Mar 1, 2016 at 14:59
  • \$\begingroup\$ Are language parser languages allowed? \$\endgroup\$ Commented Mar 1, 2016 at 16:27

1 Answer 1

1
\$\begingroup\$

JavaScript (ES6), 368 bytes

f=(s,r=[],i='',j=i+'  ',a=[])=>s<'['?([,,r[0]]=s.match(s<'0'?/("(?:\\.|[^"])*")(.*)/:/(\d+)(.*)/))[1]:s<'{'?(_=>{for(;s<']';s=r[0])a.push(f(s.slice(1),r,j));r[0]=s.slice(1)})()||/\n/.test(a)?`[
${j+a.join(`,
`+j)}
${i}]`:`[${a.join`, `}]`:(_=>{for(a=[];s<'}';s=r[0])a.push(f(s.slice(1),r,j)+': '+f(r[0].slice(1),r,j));r[0]=s.slice(1)})()||`{
${j+a.join(`,
`+j)}
${i}}`

Less golfed:

function j(s, r=[], i='') { // default to no indentation
    if (s < '0') { // string
        let a = s.match(/("(?:\\.|[^"])*")(.*)/);
        r[0] = a[2]; // pass the part after the string back to the caller
        return a[1];
    } else if (s < '[') { // number
        let a = s.match(/(\d+)(.*)/);
        r[0] = a[2]; // pass the part after the string back to the caller
        return a[1];
    } else if (s < '{') { // array
        let a = [];
        while (s < ']') { // until we see the end of the array
            s = s.slice(1);
            a.push(j(s, r, i + '  ')); // recurse with increased indentation
            s = r[0]; // retrieve the rest of the string
        }
        r[0] = s.slice(1); // pass the part after the string back to the caller
        if (/\n/.test(a.join())) { // array contained object
            return '[\n  ' + i + a.join(',\n  ' + i) + '\n' + i + ']';
        } else {
            return '[' + a.join(', ') + ']';
        }
    } else { // object
        let a = [];
        while (s < '}') { // until we see the end of the object
            s = s.slice(1);
            let n = j(s, r, i + '  ');
            s = r[0].slice(1);
            let v = j(s, r, i + '  ');
            a.push(n + ': ' + v);
            s = r[0]; // retrieve the rest of the string
        }
        r[0] = s.slice(1); // pass the part after the string back to the caller
        return '{\n  ' + i + a.join(',\n  ' + i) + '\n' + i + '}';
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.