Home > Mobile >  2D array formatting in JQ
2D array formatting in JQ

Time:08-02

I'm using jq to reformat my files to be "nice and pretty". I'm using basic '.', but this is not working as I expect.

Let's say I have structure like this:

{ "foo": { "bar": { "baz": 123 }, 
"bislot": 
[[1,2,3,4,5],
[6,7,8,9,10],
[11,12,13,14,15]]
}}

and after reformatting with jq . I'm getting output like this:

{
  "foo": {
    "bar": {
      "baz": 123
    },
    "bislot": [
      [
        1,
        2,
        3,
        4,
        5
      ],
      [
        6,
        7,
        8,
        9,
        10
      ],
      [
        11,
        12,
        13,
        14,
        15
      ]
    ]
  }
}

What I want to achieve is something like this:

{
  "foo": {
    "bar": {
      "baz": 123
    },
    "bislot":
      [[1,2,3,4,5],
      [6,7,8,9,10],
      [11,12,13,14,15]]
  }
}

So for 2D arrays every item(array) should be in one line. Any ideas how can I do this?

CodePudding user response:

As it has been pointed out already, from a JSON processor's perspective the formatting doesn't really matter. As you have noticed, jq by default pretty-prints its output. It also offers a --compact-output (or -c) option to output each JSON document into one line, which in your case would result in

jq -c . file.json
{"foo":{"bar":{"baz":123},"bislot":[[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15]]}}

If you care more about aesthetics than whether it is logically the same document or not, an easy way could be to encode all arrays within arrays as JSON, thus becoming strings, which when pretty-printing the whole document with jq won't be broken down anymore:

jq 'walk(arrays[] |= (arrays |= @json))' file.json
{
  "foo": {
    "bar": {
      "baz": 123
    },
    "bislot": [
      "[1,2,3,4,5]",
      "[6,7,8,9,10]",
      "[11,12,13,14,15]"
    ]
  }
}

Demo

Going further, you could take the output from the previous call, read it line by line back into jq, decode lines with JSON-encoded arrays using fromjson, and output the modified lines (together masquerading as JSON document). This approach uses regex matching with look-ahead and look-behind to identify (the positions of) JSON-encoded arrays.

jq 'walk(arrays[] |= (arrays |= @json))' file.json \
| jq -Rr '(
    match("^\\s (?=\"\\[)").length as $a
    | match("(?<=\\]\"),?$").offset as $b
    | .[:$a]   (.[$a:$b] | fromjson)   .[$b:]
  ) // .'
{
  "foo": {
    "bar": {
      "baz": 123,
      "baz2": 123
    },
    "bislot": [
      [1,2,3,4,5],
      [6,7,8,9,10],
      [11,12,13,14,15]
    ]
  }
}

Demo

Disclaimer: Although this outputs a valid JSON document for your sample input, this should still be regarded as an aesthetic printout. If the validity of your JSON document is a first-class concern, the actual formatting shouldn't really matter. jq's default pretty-printer, and its compact equivalent generally should fit most needs.

CodePudding user response:

You can consider combining jq with another tool (here perl):

jq . input.json | perl -0777 -pe 's/\[[^\[\]] \]/$v=$&,($v =~ s[\s][]g),$v/egs'
  • Related