1
头图

In Common Lisp, the function format is generally used to print integers. For example, the above code will print the number 233 to standard output:

 (format t "~D" 233)

In addition, format can also control the width of the printed content, fill characters, whether to print positive and negative signs, etc. For example, if you want to control the printed content to occupy at least 6 columns, you can use the following code

 (format t "~6D" 233)

If you don't use the DSL in string form, but implement a function that can achieve the same effect as keyword arguments format-decimal , the code may be as follows:

 (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)

If it is required to fill the column on the left with zeros instead of spaces, write format as follows:

 (format t "~6,'0D" 233)

format-decimal To do the same thing, you can write:

 (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 default is not to print the sign of non-negative integers, you can use the modifier @ to modify this behavior. For example, (format t "~6,'0@D" 233) would print 00+233 . A little modification can achieve the same function in 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)

In addition to @ , : is also a modifier for ---f54f23e26b0e0dd74ff05efa80ecfce3 ~D , which prints a format every 3 digits commas, for easier reading of long numbers. For example, the following code would print 00+23,333 :

 (format t "~9,'0@:D" 23333)

To do this, add a keyword argument comma-separated format-decimal control this behavior.

 (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)

In fact, the step size for printing the delimiter, as well as the comma as the delimiter, can be customized. For example, a hyphen can be printed every 4 digits instead

 (format t "~9,'0,'-,4@:D" 23333)

For format-decimal this modification is now simple

 (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)

The full text is complete.

read the original


用户bPGfS
169 声望3.7k 粉丝