How to pad numbers with JQ?
Asked Answered
D

6

6

I'd like to add leading/trailing zeros to strings from numbers — resultant string needs to contain "01" or "001" and not "1". I noticed project https://github.com/joelpurra/jq-zeros but I have jq installed from package manager (dnf, fedora) so requirement of some jqnpm is not feasible for me (at first sight), not to mention my fear of npm, as stuff sudo npm -g ruined my system several times already.

Question:

  1. these package managers for jq, are they even in process of being accepted into mainstream or not?
  2. the padding itself — how to do it without this extra library?
Drainage answered 22/11, 2020 at 18:36 Comment(0)
S
5

Given this JSON document:

7

You can achieve "007" with the following filter: (or "042" with 42)

tostring | (length | if . >= 3 then "" else "0" * (3 - .) end) as $padding | "\($padding)\(.)"
  1. tostring convert 7 into "7"
  2. If number had 3 or more digits then set padding to "" otherwise set to "0" * (3 - length). (When a string is multiplied by a number it is repeated that many time e.g. "foo" * 3 -> "foofoofoo")
  3. And append the number to the end
Stylize answered 22/11, 2020 at 18:45 Comment(0)
O
13

You could define these functions at the start of your filter or adding it to your ~/.jq file then use it to pad the numbers.

def pad_left($len; $chr):
    (tostring | length) as $l
    | "\($chr * ([$len - $l, 0] | max) // "")\(.)"
    ;
def pad_left($len):
    pad_left($len; " ")
    ;

Then to use it to pad your value with three 0s:

pad_left(3; "0")
Oxidase answered 22/11, 2020 at 19:24 Comment(0)
E
9

Based on the jq-esque definition from In jq, how to get tonumber to output decimal instead of scientific notation :

def lpad(n):
  tostring
  | if (n > length) then ((n - length) * "0") + . else . end;

As for jq module managers, there is nothing in jq’s official development pipeline, but jqnpm has nothing to do with npm, and is pretty safe to use, at least if you don’t run it with sudo.

Exocarp answered 22/11, 2020 at 21:46 Comment(1)
Nice! Here's one that works with negative numbers: def lpad(n): if . < 0 then "-" else "" end + (length | tostring | if (n > length) then ((n - length) * "0") + . else . end);Zurheide
S
5

Given this JSON document:

7

You can achieve "007" with the following filter: (or "042" with 42)

tostring | (length | if . >= 3 then "" else "0" * (3 - .) end) as $padding | "\($padding)\(.)"
  1. tostring convert 7 into "7"
  2. If number had 3 or more digits then set padding to "" otherwise set to "0" * (3 - length). (When a string is multiplied by a number it is repeated that many time e.g. "foo" * 3 -> "foofoofoo")
  3. And append the number to the end
Stylize answered 22/11, 2020 at 18:45 Comment(0)
T
3

If you are sure the number will not overflow the format digits, you can simulate a "%03d" with:

aNumber+1000|tostring[1:]
Thermobarograph answered 1/2, 2024 at 20:36 Comment(0)
S
1

Same principle as shown in this answer, but shorter:

"00\(.)"[-3:]

Some notes

  • This answer fails with non-whole numbers
  • Many (all?) answers here (including this one) fail with negative numbers and large numbers (from somewhere above 1e16)
  • This answer only returns the last three digits with (small) numbers > 999
Stern answered 9/9, 2024 at 4:8 Comment(0)
Z
0

Here is a solution that handles overflow as well. It can pad any number:

$ jq '3 as $pad | (fmax(0;.aNumber)|tostring) as $N|($N|length) as $D|[range($pad) as $_|"0"]|join("")[fmax($D; $D-$pad):]+$N' <<<'{"aNumber": 1}'
"001"
$ jq '3 as $pad | (fmax(0;.aNumber)|tostring) as $N|($N|length) as $D|[range($pad) as $_|"0"]|join("")[fmax($D; $D-$pad):]+$N' <<<'{"aNumber": 12}'
"012"
$ jq '3 as $pad | (fmax(0;.aNumber)|tostring) as $N|($N|length) as $D|[range($pad) as $_|"0"]|join("")[fmax($D; $D-$pad):]+$N' <<<'{"aNumber": 123}'
"123"
$ jq '3 as $pad | (fmax(0;.aNumber)|tostring) as $N|($N|length) as $D|[range($pad) as $_|"0"]|join("")[fmax($D; $D-$pad):]+$N' <<<'{"aNumber": 1234}'
"1234"

with any number of leading zeros:

$ jq '4 as $pad | (fmax(0;.aNumber)|tostring) as $N|($N|length) as $D|[range($pad) as $_|"0"]|join("")[fmax($D; $D-$pad):]+$N' <<<'{"aNumber": 1234}'
"1234"
$ jq '5 as $pad | (fmax(0;.aNumber)|tostring) as $N|($N|length) as $D|[range($pad) as $_|"0"]|join("")[fmax($D; $D-$pad):]+$N' <<<'{"aNumber": 1234}'
"01234"

and this handles negative numbers as well, by ignoring/treating them as 0:

$ jq '3 as $pad | (fmax(0;.aNumber)|tostring) as $N|($N|length) as $D|[range($pad) as $_|"0"]|join("")[fmax($D; $D-$pad):]+$N' <<<'{"aNumber": -123213}'
"000"
Zurheide answered 3/6, 2024 at 17:50 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.