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

  • 0
  • 0
  • 418
  • 20
  • 9

Answers

##class(Ens.Rule.FunctionSet).Pad(inputString,LengthofYourString,0)     

 Eg: w ##class(Ens.Rule.FunctionSet).Pad(1,-4,0)    

0001


 

This returns with "0000".

I need it to keep the value and add 0's infront.

Here's one way, which uses $JUSTIFY to add leading spaces, then $TRANSLATE to convert these to zeroes:

USER>s number=1

USER>w $tr($j(number,4)," ","0")
0001
USER>

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)

PHP
$string = 9;
echo str_pad($string5'0', STR_PAD_LEFT); // Resultado: 00009

$EXTRACT("0000"_val,*-3,*)

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.

For the record, the $TR abbreviation in my answer stands for $TRANSLATE

There is no $TRIM function in ObjectScript.

Another way:

set number="",$p(number,0,4)=1 w number 

0001

$P is how I do it as well and due to a quirk of $P you don't even have to set the variable first although if it is possible a value might already exist it is reccommended.

That's a good point and the code base example is useful but the question was specifically for leading zero's and the code base version might be overkill for this.

USER>w $$lpad^%qarfunc("1",4,"0")
0001

If in an alternate namespace, this would require the namespace to contain the %qarfunc, or have a routine mapping to the USER namespace.

No, according to my tests the %qarfunc routine is available in all namespaces. It comes from the CACHELIB / IRISLIB database. But I think it's a remnant of an ancient InterSystems tool called M/SQL, so I wouldn't recommend starting to rely on it in new code you're writing.

The functions from %qarfunc are actively used in system classes, so I don't think ^%qarfunc will be removed in the near future, otherwise everything will stop working.

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.

I was looking at the generated INT code for &sql(select lpad('1',4,'0'n)

Unfortunately, for COS at the moment I have not found an analogue LPADSQL.
Can you offer a documented LPADCOS ?

Also LPADSQL

USER>d $system.SQL.Shell()
SQL Command Line Shell
----------------------------------------------------
 
The command prefix is currently set to: <>.
Enter q to quit, ? for help.
USER>>select lpad('1',4,'0'n
1.      select lpad('1',4,'0'n
 
n
0001
 
1 Rows(s) Affected

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.

I think this is normally called right-justify-zero-fill:

I usually define a local function, such as:

rjzf(num,wid) Quit $Translate($Justify(num,wid)," ","0")

USER> w $$rjzf(1,4)

0001

Ben, thanks, I use the same approach.

Nothing to add to the "code base" as this solution is already here by #1 (John was the first).

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

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

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.