开发者

dc(1) and leading zeros

开发者 https://www.devze.com 2023-02-17 04:18 出处:网络
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

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 register d
  • dZ - duplicate the original number and push the count of its digits
  • dsc - duplicate that count and store it in register c
  • ld>b - load the desired digits from register d, if it's greater than the count then call macro b
  • 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 register c and increment it
  • dsc - duplicate the count and store it back to register c
  • 0n - output a zero without a newline
  • ld>b - load the desired digits from register d, if it's still greater than the incremented count then loop back to run macro b again, otherwise it will return to the caller (macro a)

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"
0

精彩评论

暂无评论...
验证码 换一张
取 消