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!
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.
$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.
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
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
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.
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.
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.
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.
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.
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.
This is the way I do it when I need to
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)
? probably the WRONG FORUM ?
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.
$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.
Hi Tomas,
Your solution, despite its beauty, is correct for single digit numbers only:
Its correct flavor (initially published by Larry Faraci) was included in my "code base" as #5, see https://community.intersystems.com/post/add-leading-zeros#comment-59096
If in an alternate namespace, this would require the namespace to contain the %qarfunc, or have a routine mapping to the USER namespace.
Also LPADSQL
I think this is normally called right-justify-zero-fill:
I usually define a local function, such as:
USER> w $$rjzf(1,4)
0001
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.
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>
For the record, the $TR abbreviation in my answer stands for $TRANSLATE
There is no $TRIM function in ObjectScript.
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 ?
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.
See:
Implied Namespace Mapping
What Is Accessible in Your Namespaces
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).
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.
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.
PHP
$string = 9;
echo str_pad($string, 5, '0', STR_PAD_LEFT); // Resultado: 00009
$EXTRACT("0000"_val,*-3,*)
Another way:
set number="",$p(number,0,4)=1 w number 0001
If you do universal LPAD, it is best $$lpad^%qarfunc, because for certain arguments may produce an incorrect result, for example:
Result:
If we are looking for more generic solution, e.g. pad <number> by zeroes yielding to the field of given <length>, let's try:
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:
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
Hi,
The solution is to use the 2 methods:
so in that case:
set Num=1
set NumWithLeadingZeros= $REPLACE($J(Num,9)," ","0")