我必须在lisp中将十进制数转换为二进制数.我在网上搜索时遇到了这段代码.
(defun :bits (value &optional (size 64)) (format t "~v,'~B" size value))
所以请解释一下代码的每个属性将做什么.
因此(format nil "~B" 23)
将以二进制形式输出数字:
> (format nil "~B" 23) "10111"
但是我们想要指定输出字符串的大小,我们可以通过在格式字符串中添加大小作为前缀来实现.
> (format nil "~8B" 23) " 10111"
但我们不想用空格填充它.我们想用它填充它~
.
> (format nil "~8,'~B" 23) "~~~10111"
现在我们不想在格式字符串中硬编码输出的大小,我们希望将其作为参数传入.这是~v进来的地方:
> (format nil "~v,'~B" 8 23) "~~~10111"
现在注意我已经nil
作为第二个参数传递而不是t
.传递nil意味着format返回格式化的字符串而不是打印它.你可能宁愿这样做.
Mongus Pong的回答描述了你正在寻找的代码的实际行为,但我认为总是值得一提的是在哪里找到答案.在Common Lisp的HyperSpec是Common Lisp的文档的最佳来源,但也有是有点难以阅读其中的一部分.有时,格式指令的文档可能有点密集.在这种情况下,您需要查看几个部分,因为示例中的某些内容不仅适用于二进制指令~B.
您想要从22.3格式化输出开始,它描述了格式字符串的语法:
指令由波浪号,由逗号分隔的可选前缀参数,可选的冒号和符号修饰符以及指示这是什么类型的指令的单个字符组成.at-sign和colon修饰符之间没有必需的顺序.指令字符的大小写被忽略.前缀参数标记为带符号(符号是可选的)十进制数,或单引号后跟一个字符.例如,~5,'0d可用于以五个列中的前导零打印十进制基数的整数,或者~5,'*d来获得前导星号.
所以我们期望看到一个代字号,然后(可选)参数用冒号分隔,一个(可选)符号(@),一个(可选)冒号(:)和实际前缀指令(区分大小写).这意味着
~v,'~B
被分解为
~ ; initial tilde v ; prefix parameter (could also be V) , ; separator between prefix parameters '~ ; prefix parameter (character following single quote) B ; directive (could also be b)
因此,我们有两个前缀参数: v和〜,而指令是乙.文档中的下一段描述了v作为前缀参数时的作用:
代替指令的前缀参数,可以使用V(或v).在这种情况下,format将args中的参数作为指令的参数.参数应该是整数或字符.如果V参数使用的arg为nil,则效果就好像省略了参数一样.
现在,为了找出~B的一般情况,你需要看到22.3.2.3 Tilde B:Binary,尽管它会将你的重定向转移到其他地方:
这就像~D但是以二进制基数(基数2)而不是十进制打印.因此,完整形式是~mincol,padchar,commachar,comma-intervalB.
该文档描述了可接受的前缀参数(mincol,padchar,commachar和逗号间隔).这些是从左到右填写的.例子~v,'B有两个,所以v是mincol而'是padchar.但是我们仍然需要看到22.3.2.2 Tilde D:Decimal,其中每个都意味着:
~mincolD使用mincol的列宽; 如果数字的数字和符号需要少于mincol列,则在左侧插入空格.如果该数字不适合mincol列,则根据需要使用其他列.
~mincol,padcharD使用padchar作为填充字符而不是空格.
...:修饰符导致在数字组之间打印逗号; commachar可用于更改用作逗号的字符.逗号间隔必须是整数,默认为3.当对任何这些指令赋予:修饰符时,将在逗号间隔数字组之间打印commachar.
所以,mincol,结果的宽度是v,这意味着它将从参数列表中读取,padchar,填充字符是〜.从而:
CL-USER> (bits 13 10) ~~~~~~1101 ; 10 characters wide, padded with ~ CL-USER> (bits 1022 10) 1111111110 ; 10 characters wide, no need for padding CL-USER> (bits 1022 11) ; 11 characters with, padded with ~ ~1111111110