dc(1) and leading zeros
I've got a shell script and I do some calculations with dc(1).
I need to have one number printed with leading zeros; I can't find an easy and straightforward way to do this with dc itself, but the manpage does mention:
Z
Pops a value off the stack, calculates the number of digits it has (or number of characters, if it is a string) and pushes that number. The digit count for a nu开发者_如何学Pythonmber does not include any leading zeros, even if those appear to the right of the radix point.
Which sort of implies there is an easy and straightforward way ...
I know there are a zillion-and-one method of accomplishing this, and I the script is running happily with one of them. I'm just curious ;-)
Give this a try:
Enter:
[lc1+dsc0nld>b]sb
[sddZdscld>bp]sa
999
12lax
Output:
000000999
Enter:
3lax
Output:
999
The original number is left on the stack after the macro ends. Registers used: a
(macro), b
(macro), c
(count), d
(digits).
Explanation:
Macro a
does the setup, calls b
and prints the original number.
sd
- store the number of digits to be output in registerd
dZ
- duplicate the original number and push the count of its digitsdsc
- duplicate that count and store it in registerc
ld>b
- load the desired digits from registerd
, if it's greater than the count then call macrob
p
- print the original number
Macro b
outputs zeros until the count is greater than the number of desired digits
lc1+
- load the count from registerc
and increment itdsc
- duplicate the count and store it back to registerc
0n
- output a zero without a newlineld>b
- load the desired digits from registerd
, if it's still greater than the incremented count then loop back to run macrob
again, otherwise it will return to the caller (macroa
)
To use an arbitrary leading character:
[lclkZ+dsclknld>b]sb
[sksddZdscld>bp]sa
999 14 [ ] lax
999
[abc] 12 [-] lax
---------abc
In addition to the other registers, it uses k
to store the character (which could actually be more than one):
[XYZ] 6 [def] lax
defXYZ
8 [ab] lax
abababXYZ
4 [ghjikl] lax
ghijklXYZ
The fill strings are used whole so the result may be longer than you asked for if the desired length number is larger than the length of the original string, but smaller than the length of the two strings (or integer multiples).
Here is an example, albeit inelegant. This prints out 999 with 2 leading zeros. You'll need to duplicate the code for more digits.
#Push number to print on stack
999
# macro to print a zero
[[0]P]sa
# Print a zero if less than 5 digits
dZ5>a
# Print a zero if less than 4 digits
dZ4>a
# Print a zero if less than 3 digits
dZ3>a
# Print a zero if less than 2 digits
dZ2>a
# Print out number
p
The solutions given work for decimal numbers. For hex (as well as for any other input) radix use. e.g.
c=18A; dc <<< "16i${c^^}d0r[r1+r10/d0<G]dsGx4+r-[1-[0]nlGx]sY[d0<Y]dsGxr10op"
^ radix formatted length ^ ^ leading symbol
You may also try
c=19; dc <<< "10i${c^^}d0r[r1+r10/d0<G]dsGx4+r-[1-[_]nlGx]sY[d0<Y]dsGxr10op"
c=607; dc <<< " 8i${c^^}d0r[r1+r10/d0<G]dsGx8+r-[1-[*]nlGx]sY[d0<Y]dsGxr10op"
c=1001; dc <<< " 2i${c^^}d0r[r1+r10/d0<G]dsGx8+r-[1-[ ]nlGx]sY[d0<Y]dsGxr10op"
G
and Y
are the registers used. First the number of digits is counted on the stack, then the number of symbols to be printed.
c=607; dc <<< "8i${c^^}d0r[r1+r10/d0<G]dsGx f 8+r-[1-[*]nlGx]sY f [d0<Y]dsGxr10op"
精彩评论