我有一个 shell 脚本,我用 dc(1) 做了一些计算。
我需要打印一个带有前导零的数字;我找不到使用 dc 本身执行此操作的简单直接的方法,但手册页确实提到:
Z
从堆栈中弹出一个值,计算它的位数(或字符数,如果它是一个字符串)并压入该数字。数字的位数不包括任何前导零,即使它们出现在小数点的右侧。
这意味着有一种简单直接的方法......
我知道有一种千千万万的方法可以实现这一点,而且我的脚本与其中一个一起运行得很愉快。我只是好奇 ;-)
试试这个:
进入:
[lc1+dsc0nld>b]sb
[sddZdscld>bp]sa
999
12lax
输出:
000000999
进入:
3lax
输出:
999
宏结束后,原始数字留在堆栈上。使用的寄存器:(a
宏),b
(宏),c
(计数),d
(数字)。
解释:
宏a
进行设置、调用b
和打印原始号码。
sd
- 将要输出的位数存储在寄存器中d
dZ
- 复制原始数字并推动其位数dsc
- 复制该计数并将其存储在寄存器中c
ld>b
- 从寄存器加载所需的数字d
,如果它大于计数,则调用宏b
p
- 打印原始号码宏b
输出零,直到计数大于所需位数
lc1+
- 从寄存器加载计数c
并增加它dsc
- 复制计数并将其存储回寄存器c
0n
- 输出不带换行符的零ld>b
- 从寄存器加载所需的数字d
,如果它仍然大于递增的计数,则循环返回以b
再次运行宏,否则它将返回给调用者(宏a
)要使用任意前导字符:
[lclkZ+dsclknld>b]sb
[sksddZdscld>bp]sa
999 14 [ ] lax
999
[abc] 12 [-] lax
---------abc
除了其他寄存器之外,它还用于k
存储字符(实际上可能不止一个):
[XYZ] 6 [def] lax
defXYZ
8 [ab] lax
abababXYZ
4 [ghjikl] lax
ghijklXYZ
填充字符串是整体使用的,因此如果所需的长度数大于原始字符串的长度,但小于两个字符串的长度(或整数倍),结果可能比您要求的要长。
这是一个例子,虽然不优雅。这将打印出 999 和 2 个前导零。您需要复制代码以获得更多数字。
#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
给出的解决方案适用于十进制数。对于十六进制(以及任何其他输入)基数使用。例如
c=18A; dc <<< "16i${c^^}d0r[r1+r10/d0<G]dsGx4+r-[1-[0]nlGx]sY[d0<Y]dsGxr10op"
^ radix formatted length ^ ^ leading symbol
你也可以试试
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
并且Y
是使用的寄存器。首先计算堆栈上的位数,然后计算要打印的符号数。
c=607; dc <<< "8i${c^^}d0r[r1+r10/d0<G]dsGx f 8+r-[1-[*]nlGx]sY f [d0<Y]dsGxr10op"