Question
· Oct 23, 2018

Add Leading Zeros

I'm trying to format a filed, and I need to add leading zeros infront with a length of 4.

Example:

Before: 1

After: 0001

Discussion (30)7
Log in or sign up to continue

I think that is my preferred method as well, but it depends to some extent what you are going to do with the result, and what you want to happen if the input number is too big. This $J solution will always return all the characters input, which may be the safest thing. (Though any space characters inside the input will get converted to zeros.)

When the fail mode needs to still return the same length string, e.g. to avoid messing up some fixed length message format, it might be best to use $E(), e.g.

W $E("0000"_number,$L(a)+1,*)

I've also seen the following used, but I'm not sure I recommend it. So many interesting ways it could go wrong!

w $E(number+10000,2,999)

This does work. I think the only downside is if you were to apply this to longer numbers. For example, an invoice number with 9 digits you'd have to write "000000000". As far as readability, you'd have to count those zeroes every time. For this reason, I'd say the combination of $TRIM and $JUSTIFY would be more appropriate since you'd alleviate how to count the zeroes.

Thanks, Larry,
Adding your variant to the "code base".
As most of others, your solution needs *  length correction  * which I'm putting aside from Xecute to improve readability.

lpad(number=1,length=4)
  new code,i,z,sign
  set number=+number
  set sign="" set:number<0 sign="-",number=-number
  set code($increment(code))="w sign_$tr($j(number,length),"" "",""0"")"
  set:length<$l(number) length=$l( number) ;* length correction *
  set code($increment(code))="w sign_$e(1E"_length_"+number,2,*)"
  set code($increment(code))="w sign_$e(10**length+number,2,*)"
  set code($increment(code))="w sign_$e($tr($j("""",length),"" "",0)_number,*-length+1,*)"
  set code($increment(code))="s $P(z,""0"",length)=number w sign_$E(z,*-(length-1),*)"
  for i=1:1:code write code(i),"  => ",?60 xecute code(i) write !
  quit

Please, never ever rely on undocumented APIs. They may be taken out or change semantics without further notice. The best you get is "use at your own risk" if you think you have to.
There is a plethora of one-liner suggestions here you can use for the same purpose. No need to walk into undocumented InterSystems system code for an LPAD function.

While adding the length check is valid for a pure coding solution, the most practical reason where leading zero's are necessary is for values that are required to be a fixed length such as SSN's.

If a value initially  exceeded that fixed length, it most likely would have been trapped out as an invalid entry before it reached the length adjustment code.

If you do universal LPAD, it is best $$lpad^%qarfunc, because for certain arguments may produce an incorrect result, for example:

#define lpad(%s,%len,%pad) $tr($j(%s,%len)," ",%pad)
   
s s="a b",len=8,pad="0"
   
w $$$lpad(s,len,pad),!
 ,$$lpad^%qarfunc(s,len,pad),!
 ,$$$lpad(s,len,s),!
 ,$$lpad^%qarfunc(s,len,s),!

Result:

USER>^test
00000a0b
00000a b
aaaaaaab
a ba a b

If we are looking for more generic solution, e.g. pad <number> by zeroes yielding to the field of given <length>, let's try:

lpad(number=1,length=4)
  new code
  set code($increment(code))="w $tr($j(number,length),"" "",""0"")"
  set code($increment(code))="w $e(1E"_length_"+number,2,*)"
  set code($increment(code))="w $e(10**length+number,2,*)"
  set code($increment(code))="w $e($tr($j("""",length),"" "",0)_number,*-length+1,*)"
  for i=1:1:code write code(i)," => " xecute code(i) write !
  quit

Some  results are:

for n=999,9999,99999 d lpad^ztest(n,4) w !
 
w $tr($j(number,length)," ","0") => 0999
w $e(1E4+number,2,*) => 0999
w $e(10**length+number,2,*) => 0999
w $e($tr($j("",length)," ",0)_number,*-length+1,*) => 0999
 
w $tr($j(number,length)," ","0") => 9999
w $e(1E4+number,2,*) => 9999
w $e(10**length+number,2,*) => 9999
w $e($tr($j("",length)," ",0)_number,*-length+1,*) => 9999
 
w $tr($j(number,length)," ","0") => 99999
w $e(1E4+number,2,*) => 09999
w $e(10**length+number,2,*) => 09999
w $e($tr($j("",length)," ",0)_number,*-length+1,*) => 9999

Only the first solution (John's one) provides valid result even with "bad" input data ($length(99999) > 4). Others can't be amended this way without extra efforts irrelevant to this tiny task. Just to complete it:

lpad(number=1,length=4)
 new code,i
 set code($i(code))="w $tr($j(number,length),"" "",""0"")"
 set code($i(code))="w $e(1E"_$s(length>$l(number):length,1:$l(number))_"+number,2,*)"
 set code($i(code))="w $e(10**$s(length>$l(number):length,1:$l(number))+number,2,*)"
 set code($i(code))="w $e($tr($j("""",$s(length>$l(number):length,1:$l(number))),"" "",0)_number,*-$s(length>$l(number):length,1:$l(number))+1,*)"
 for i=1:1:code write code(i)," => ",?60 xecute code(i) write !
 quit

Now all solutions become correct even with the <number> >= 99999, but only the first one keeps its simplicity.

Try this:

ROU>s val="sd123X"             ; value to be justified

ROU>s len=9                             ; length of the total string

ROU>k z                                      ; make sure z is undefined

ROU>s $P(z,"0",len)=val        ; set z to value with leading zeros

ROU>s val=$E(z,*-(len-1),*)   ; trim value to required length

ROU>w !,val

000sd123X