共计 4502 个字符,预计需要花费 12 分钟才能阅读完成。
在 Common Lisp 中,打印整数个别用函数format
。例如,下面的代码会往规范输入中打印出 233 这个数字:
(format t "~D" 233)
除此之外,format
还能够管制打印内容的宽度、填充字符、是否打印正负号等方面。例如,要管制打印的内容至多占据 6 列的话,能够用如下代码
(format t "~6D" 233)
如果不应用字符串模式的 DSL,而是以关键字参数的形式来实现一个可能达到同样成果的函数format-decimal
,代码可能如下:
(defun format-decimal (n | |
&key | |
mincol) | |
" 打印整数 N 到规范输入。MINCOL 如果不为 NIL,则示意所打印的内容至多要占据的列数。" | |
;; 通过取余的形式失去 N 的每一位并一一入栈,之后出栈的程序就是从左到右打印的程序了。(let ((digits '())) | |
(cond ((zerop n) | |
(push 0 digits)) | |
(t | |
(do ((n n (truncate n 10))) | |
((zerop n)) | |
(push (rem n 10) digits)))) | |
;; 打印出填充用的空格。(when (and (integerp mincol) (> mincol (length digits))) | |
(dotimes (i (- mincol (length digits))) | |
(declare (ignorable i)) | |
(princ #\Space))) | |
(dolist (digit digits) | |
(princ (code-char (+ digit (char-code #\0))))))) | |
(format-decimal 233 :mincol 6) |
如果要求用数字 0 而不是空格来填充左侧的列,用 format
的写法如下:
(format t "~6,'0D" 233)
format-decimal
想要做到同样的事件,能够这么写:
(defun format-decimal (n | |
&key | |
mincol | |
(padchar #\Space)) | |
" 打印整数 N 到规范输入。MINCOL 如果不为 NIL,则示意所打印的内容至多要占据的列数。PADCHAR 表达式为了填充多余的列时所用的字符。" | |
(check-type mincol (or integer null)) | |
(check-type padchar character) | |
;; 通过取余的形式失去 N 的每一位并一一入栈,之后出栈的程序就是从左到右打印的程序了。(let ((digits '())) | |
(cond ((zerop n) | |
(push 0 digits)) | |
(t | |
(do ((n n (truncate n 10))) | |
((zerop n)) | |
(push (rem n 10) digits)))) | |
;; 打印出填充用的空格。(when (and (integerp mincol) (> mincol (length digits))) | |
(dotimes (i (- mincol (length digits))) | |
(declare (ignorable i)) | |
(princ padchar))) | |
(dolist (digit digits) | |
(princ (code-char (+ digit (char-code #\0))))))) | |
(format-decimal 233 :mincol 6 :padchar #\0) |
-D
默认是不会打印非负整数的符号的,能够用修饰符 @
来批改这个行为。例如,(format t "~6,'0@D" 233)
会打印出 00+233
。略微批改一下就能够在format-decimal
中实现同样的性能
(defun format-decimal (n | |
&key | |
mincol | |
(padchar #\Space) | |
signed) | |
" 打印整数 N 到规范输入。MINCOL 如果不为 NIL,则示意所打印的内容至多要占据的列数。PADCHAR 表达式为了填充多余的列时所用的字符。" | |
(check-type mincol (or integer null)) | |
(check-type padchar character) | |
(flet ((to-digits (n) | |
;; 通过取余的形式失去 N 的每一位并一一入栈,之后出栈的程序就是从左到右打印的程序了。(let ((digits '())) | |
(cond ((zerop n) | |
(push #\0 digits)) | |
(t | |
(do ((n n (truncate n 10))) | |
((zerop n)) | |
(push (code-char (+ (rem n 10) (char-code #\0))) digits)))) | |
digits))) | |
;; 通过取余的形式失去 N 的每一位并一一入栈,之后出栈的程序就是从左到右打印的程序了。(let ((digits (to-digits (abs n)))) | |
(when (or signed (< n 0)) | |
(push (if (< n 0) #\- #\+) digits)) | |
;; 打印出填充用的空格。(when (and (integerp mincol) (> mincol (length digits))) | |
(dotimes (i (- mincol (length digits))) | |
(declare (ignorable i)) | |
(princ padchar))) | |
(dolist (digit digits) | |
(princ digit))))) | |
(format-decimal 233 :mincol 6 :padchar #\0 :signed t) |
除了 @
之外,:
也是一个 ~D
的修饰符,它能够让 format
每隔 3 个数字就打印出一个逗号,不便浏览比拟长的数字。例如,下列代码会打印出00+23,333
:
(format t "~9,'0@:D" 23333)
为此,给 format-decimal
新增一个关键字参数 comma-separated
来管制这一行为。
(defun format-decimal (n | |
&key | |
comma-separated | |
mincol | |
(padchar #\Space) | |
signed) | |
" 打印整数 N 到规范输入。COMMA-SEPARATED 如果为 T,则每打印 3 个字符就打印一个逗号。MINCOL 如果不为 NIL,则示意所打印的内容至多要占据的列数。PADCHAR 示意填充多余的列时所用的字符。SIGNED 管制是否显示非负整数的加号。" | |
(check-type comma-separated boolean) | |
(check-type mincol (or integer null)) | |
(check-type padchar character) | |
(check-type signed boolean) | |
(flet ((to-digits (n) | |
;; 通过取余的形式失去 N 的每一位并一一入栈,之后出栈的程序就是从左到右打印的程序了。(let ((digits '())) | |
(cond ((zerop n) | |
(push #\0 digits)) | |
(t | |
(do ((count 0 (1+ count)) | |
(n n (truncate n 10))) | |
((zerop n)) | |
(when (and comma-separated (> count 0) (zerop (rem count 3))) | |
(push #\, digits)) | |
(push (code-char (+ (rem n 10) (char-code #\0))) digits)))) | |
digits))) | |
;; 通过取余的形式失去 N 的每一位并一一入栈,之后出栈的程序就是从左到右打印的程序了。(let ((digits (to-digits (abs n)))) | |
(when (or signed (< n 0)) | |
(push (if (< n 0) #\- #\+) digits)) | |
;; 打印出填充用的空格。(when (and (integerp mincol) (> mincol (length digits))) | |
(dotimes (i (- mincol (length digits))) | |
(declare (ignorable i)) | |
(princ padchar))) | |
(dolist (digit digits) | |
(princ digit))))) | |
(format-decimal -23333 :comma-separated t :mincol 9 :padchar #\0 :signed t) |
事实上,打印分隔符的步长,以及作为分隔符的逗号都是能够定制的。例如,能够改为每隔 4 个数字打印一个连字符
(format t "~9,'0,'-,4@:D" 23333)
对于 format-decimal
来说这个批改当初很简略了
(defun format-decimal (n | |
&key | |
(commachar #\,) | |
(comma-interval 3) | |
comma-separated | |
mincol | |
(padchar #\Space) | |
signed) | |
" 打印整数 N 到规范输入。COMMACHAR 示意当须要打印分隔符时的分隔符。COMMA-INTERVAL 示意当须要打印分隔符时须要距离的步长。COMMA-SEPARATED 如果为 T,则每打印 3 个字符就打印一个逗号。MINCOL 如果不为 NIL,则示意所打印的内容至多要占据的列数。PADCHAR 示意填充多余的列时所用的字符。SIGNED 管制是否显示非负整数的加号。" | |
(check-type commachar character) | |
(check-type comma-interval integer) | |
(check-type comma-separated boolean) | |
(check-type mincol (or integer null)) | |
(check-type padchar character) | |
(check-type signed boolean) | |
(flet ((to-digits (n) | |
;; 通过取余的形式失去 N 的每一位并一一入栈,之后出栈的程序就是从左到右打印的程序了。(let ((digits '())) | |
(cond ((zerop n) | |
(push #\0 digits)) | |
(t | |
(do ((count 0 (1+ count)) | |
(n n (truncate n 10))) | |
((zerop n)) | |
(when (and comma-separated (> count 0) (zerop (rem count comma-interval))) | |
(push commachar digits)) | |
(push (code-char (+ (rem n 10) (char-code #\0))) digits)))) | |
digits))) | |
;; 通过取余的形式失去 N 的每一位并一一入栈,之后出栈的程序就是从左到右打印的程序了。(let ((digits (to-digits (abs n)))) | |
(when (or signed (< n 0)) | |
(push (if (< n 0) #\- #\+) digits)) | |
;; 打印出填充用的空格。(when (and (integerp mincol) (> mincol (length digits))) | |
(dotimes (i (- mincol (length digits))) | |
(declare (ignorable i)) | |
(princ padchar))) | |
(dolist (digit digits) | |
(princ digit))))) | |
(format-decimal -23333 :commachar #\- :comma-interval 4 :comma-separated t :mincol 9 :padchar #\0 :signed t) |
全文完。
浏览原文
正文完