Written by

Question Kenny Hill · 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

Comments

Vivek Ranjan · Oct 23, 2018

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

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

0001

0
Kenny Hill  Oct 23, 2018 to Vivek Ranjan

This returns with "0000".

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

0
Peter Steiwer  Oct 23, 2018 to John Murray

This is the way I do it when I need to

0
Mike.W  Oct 25, 2018 to John Murray

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)
0
Robert Cemper  Oct 23, 2018 to Luccas Marra do Amaral

? probably the WRONG FORUM ?  devil

0
Mack Altman  Oct 26, 2018 to Robert Cemper

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.

0
David Underhill  Nov 1, 2018 to Tomas Vaverka

$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.

0
Mack Altman  Oct 26, 2018 to Vitaliy Serdtsev

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

0
Vitaliy Serdtsev  Oct 29, 2018 to Vitaliy Serdtsev

Also LPADSQL
USER><FONT COLOR="#0000ff">d $system</FONT><FONT COLOR="#008080">.SQL</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#0000ff">Shell</FONT><FONT COLOR="#000000">()</FONT>
SQL Command Line Shell

The command prefix is currently set to: <>. Enter q to quit, ? for help. USER>><FONT COLOR="#0000ff">select </FONT><FONT COLOR="#008000">lpad</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#008080">'1'</FONT><FONT COLOR="#000000">,4,</FONT><FONT COLOR="#008080">'0'</FONT><FONT COLOR="#000000">) </FONT><FONT COLOR="#008000">n</FONT>

  1.  <FONT COLOR="#0000ff">select&nbsp;</FONT><FONT COLOR="#008000">lpad</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#008080">'1'</FONT><FONT COLOR="#000000">,4,</FONT><FONT COLOR="#008080">'0'</FONT><FONT COLOR="#000000">)&nbsp;</FONT><FONT COLOR="#008000">n</FONT>
    

n 0001

1 Rows(s) Affected

0
Ben Bishop  Nov 1, 2018 to Alexey Maslov

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

0
Alexey Maslov  Nov 1, 2018 to Larry Faraci

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
0
John Murray · Oct 23, 2018

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>
0
John Murray  Oct 29, 2018 to Mack Altman

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

There is no $TRIM function in ObjectScript.

0
Vitaliy Serdtsev  Oct 29, 2018 to John Murray

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.

0
Gerd Nachtsheim  Nov 1, 2018 to Vitaliy Serdtsev

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.

0
Vitaliy Serdtsev  Nov 1, 2018 to Gerd Nachtsheim

I was looking at the generated INT code for <FONT COLOR="#800080">&sql(</FONT><FONT COLOR="#0000ff">select </FONT><FONT COLOR="#008000">lpad</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#008080">'1'</FONT><FONT COLOR="#000000">,4,</FONT><FONT COLOR="#008080">'0'</FONT><FONT COLOR="#000000">) </FONT><FONT COLOR="#008000">n</FONT><FONT COLOR="#800080">)</FONT>

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

0
John Murray  Oct 26, 2018 to Mack Altman

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.

0
Alexey Maslov  Nov 1, 2018 to Ben Bishop

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).

0
Larry Faraci  Nov 2, 2018 to Alexey Maslov

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.

0
David Underhill  Nov 2, 2018 to Alexey Maslov

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.

0
Luccas Marra do Amaral · Oct 23, 2018

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

0
Tomas Vaverka · Oct 23, 2018

Another way:

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

0001
0
Vitaliy Serdtsev · Oct 30, 2018

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

<FONT COLOR="#0000ff">#define </FONT><FONT COLOR="#000000">lpad(%s,%len,%pad) </FONT><FONT COLOR="#0000ff">$tr($j(%s,%len),</FONT><FONT COLOR="#008000">" "</FONT><FONT COLOR="#0000ff">,%pad)
   
s </FONT><FONT COLOR="#800000">s</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#008000">"a b"</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">len</FONT><FONT COLOR="#000000">=8,</FONT><FONT COLOR="#800000">pad</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#008000">"0"
   
</FONT><FONT COLOR="#0000ff">w $$$lpad</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#800000">s</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">len</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">pad</FONT><FONT COLOR="#000000">),!
 ,</FONT><FONT COLOR="#0000ff">$$</FONT><FONT COLOR="#ff0000">lpad</FONT><FONT COLOR="#000000">^%qarfunc(</FONT><FONT COLOR="#800000">s</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">len</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">pad</FONT><FONT COLOR="#000000">),!
 ,</FONT><FONT COLOR="#0000ff">$$$lpad</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#800000">s</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">len</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">s</FONT><FONT COLOR="#000000">),!
 ,</FONT><FONT COLOR="#0000ff">$$</FONT><FONT COLOR="#ff0000">lpad</FONT><FONT COLOR="#000000">^%qarfunc(</FONT><FONT COLOR="#800000">s</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">len</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">s</FONT><FONT COLOR="#000000">),!</FONT>
Result:
USER><FONT COLOR="#0000ff">d </FONT><FONT COLOR="#000000">^test</FONT>
<FONT COLOR="red">00000a0b</FONT>
<FONT COLOR="green">00000a b</FONT>
<FONT COLOR="red">aaaaaaab</FONT>
<FONT COLOR="green">a ba a b</FONT>
0
Alexey Maslov · Nov 1, 2018

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") => 0999w $e(1E4+number,2,*) => 0999w $e(10**length+number,2,*) => 0999w $e($tr($j("",length)," ",0)_number,*-length+1,*) => 0999w $tr($j(number,length)," ","0") => 9999w $e(1E4+number,2,*) => 9999w $e(10**length+number,2,*) => 9999w $e($tr($j("",length)," ",0)_number,*-length+1,*) => 9999w $tr($j(number,length)," ","0") => 99999w $e(1E4+number,2,*) => 09999w $e(10**length+number,2,*) => 09999w $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.

0
Larry Faraci · Nov 1, 2018

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

0
Stas Rabkin · Jan 28, 2020

Hi,

The solution is to use the 2 methods:

  •  $JUSTIFY($J) - For Adding leading spaces (" ") 
  •  $REPLACE - For Replasing the spaces to zeros.

so in that case:

set Num=1

set NumWithLeadingZeros= $REPLACE($J(Num,9)," ","0")

0