jq
jq copied to clipboard
pad function
Hi!
Can you consider to add a builtin pad(n) function to jq?
Something like this: def pad(n): if n==0 then (.) else "0" + (.) | pad(n - 1) end;
Congratulations for this great tool!
Maybe there could be a left pad (lpad) as above and a corresponding right pad (rpad) function.
Any updates about this? Regards!
How about something along this line? It's not recursive, but it's likely pretty fast.
def lpad(string;len;fill):
if len == 0 then string else (fill * len)[0:len] + string end;
def rpad(string;len;fill):
if len == 0 then string else string + (fill * len)[0:len] end;
If you want to pad string to make the result have the expected length, def lpad(string; len; fill): fill * (len - (string|length)) + string;
(or def lpad(len; fill): fill * (len - length) + .;
) would be correct.
@DavidFetter: those defs are not idiomatic. As in @itchyny's second example, it would be more idiomatic for the string to be presented as input to the filter. It would also be in keeping with jq to use tostring
on the input. So, allowing for the possibility that (fill|length) > 1, one might consider:
def lpad($len; $fill): tostring | ($len - length) as $l | ($fill * $l)[:$l] + .;
By the way what's the difference of ($str * $l)[:$l]
and ($str * $l)
?
Ahhhh, sorry, ignore my comment! It is different when ($str | length) != 1
as pkoppstein already commented out. Sorry.
Adjusted per comments, and thanks for looking at this!
By the way it doesn't work for multi-width characters, if you really want to pad spaces to strings to make them fit to a fixed width in terminals (wrap text by a frame, for example). String length and displayed width are different things.
OK! I 've seen a lot of options here jeje. Are we going to have a pad() function or similar in the next release of jq?
Thanks!
Add some performance tests:
Testing 1000 times [def pad(n): if n==0 then (.) else "0" + (.) | pad(n - 1) end]
time for i in $(seq 1000); do echo '{"test":"1"}' | jq -r 'def pad(n): if n==0 then (.) else "0" + (.) | pad(n - 1) end; .test | pad(4)'; done
real 0m3,856s
user 0m2,775s
sys 0m0,750s
Testing 1000 times [def lpad(string;len;fill): if len == 0 then string else (fill * len)[0:len] + string end]:
time for i in $(seq 1000); do echo '{"test":"1"}' | jq -r 'def lpad(string;len;fill): if len == 0 then string else (fill * len)[0:len] + string end; lpad(.test;4;"0")'; done
real 0m4,218s
user 0m2,964s
sys 0m0,878s
Could it also handle multi-character fill strings? Then the fill multiplier would be (total_length - string_length) / fill_length, rounded up. As-is, it multiplies a multicharacter fill_string a lot more than it needs to before truncating it (e.g., if the fill-string is already long enough to handle the whole field width), but it still works just fine. Maybe it could accommodate for this if it were an internal function.