format
;; Common Lisp 的 format 相当复杂,format 有 4 个输出的目的地:
;; - 标准输出(t)
;; - 带有填充指针的字符串
;; - 流
;; - nil(返回字符串)
;;; ~%,控制换行
(format t "hello~%world")
;; 输出:
;; hello
;; world
;;; 控制小数位数:
pi ; => 3.141592653589793d0
;; 默认是小数后两位
(format nil "~$" pi) ; => "3.14"
;; 前置参数(prefix parameter)控制打印浮点数的位数
(format nil "~3$" pi) ; => "3.142"
;;; ~v,可以从参数列表中取值来做前置参数的值:
;;; 从参数列表中取“3”作为前置参数
(format t "~v$" 3 pi) ; => 3.142
;;; ~#,字符串参数之后的剩余参数个数将作为 ~# 的取值:
(format t "~#$" pi nil nil) ; => 3.142
;;; ~:,让 ~D 输出的十进制数字以逗号分割:
(format t "~:d" 1000) ; => 1,000
;;; ~S 和 ~A 可将 NIL 输出成():
(format t "~:a" nil) ; => ()
(format t "~:S" nil) ; => ()
;;; ~c 可将不可打印的字符按名字输出:
(format t "~:C" #\Tab) ; => Tab
;;; ~@,给数字加上正负号:
(format t "~@d" -1000) ; => -1000
;;; 还可以和 ~: 结合:
(format t "~:@d" -1000) ; => -1,000
;;; 和 ~c 可将字符按字面字符打印出来:
(format t "~@C" #\a) ; => #\a
;;; ~&、~%,都是产生新的行,和 ~% 不同的是,~& 只有在没有位于一行开始处才换行。
;;; ~d,打印数字,支持前缀参数,第一个参数为输出的最小宽度:
(format nil "~10d" 100) ; => " 100"
;; 第二个参数指出数字之前的占位符号(默认是空格):
(format nil "~10,'0d" 100) ; => "0000000100"
;; 第三个参数配合冒号,可以指定分割符:
(format nil "~,,'.:d" 1000) ; => "1.000"
;; 第四个参数指定多少位才分割符,每一位就分割,其他都好都是做占位:
(format nil "~,,'|,1:d" 1000) ; => "1|0|0|0"
;;; ~x, ~o, ~b,分别指十六进制、八进制和二进制,和 ~d 一样的使用方法
;;; ~r,控制 2~36 之间的进制,如二进制:
(format nil "~2r" 10) ; => "1010"
;;; ~r 有趣的地方在于:不给参数可以打印数字的英文单词:
(format nil "~r" 1) ; => "one"
(format nil "~r" 100) ; => "one hundred"
(format nil "~r" 1000) ; => "one thousand"
;; 如果加 ~:,可以让它成为序数:
(format nil "~:r" 1000) ; => "one thousandth"
;; 加 ~@ 可以让它成为罗马字符:
(format nil "~@r" 1) ; => "I"
;; 配合 ~: 可以让它产生旧式的罗马字符:
(format nil "~@r" 1234) ; => "MCCXXXIV"
;;; ~p,如果参数不是1,将打印个字符“s“,用来解决复数问题:
(format nil "~p" 0) ; => "s"
(format nil "~p" 1) ; => ""
;;; ~(,控制大小写:
;; 全部转成小写
(format nil "~(~A~)" "HELLO WORLD") ; => "hello world"
;; 配合 ~@,让首字符大写:
(format nil "~@(~A~)" "HELLO WORLD") ; => "Hello world"
;; 配合 ~:,让单词首字母大写:
(format nil "~:(~A~)" "HELLO WORLD") ; => "Hello World"
;; ~: 结合 ~@,让所有字母大写:
(format nil "~:@(~A~)" "hello world") ; => "HELLO WORLD"
;;; ~[~],按数值索引取内容:
(format t "~[1~;2~;~]" 0) ; => 1
(format t "~[1~;2~;~]" 1) ; => 2
;; 和 ~: 配合在一起,True 和 False 的条件选择:
(format t "~:[F~;T~]" 1) ; => T
(format t "~:[F~;T~]" nil) ; => F
;; 和 ~@ 配合在一起,可以只支持一条子句:
(format t "~@[x=~a~]~@[y=~a~]" nil nil) ; => NIL
(format t "~@[x=~a~]~@[y=~a~]" nil 1) ; => y=1
(format t "~@[x=~a~]~@[y=~a~]" 1 2) ; => x=1y=2
;;; ~{~},迭代,需要接受一个列表:
(format t "~{~a~%~}" (list 1 2 3 4))
;; 输出:
;; 1
;; 2
;; 3
;; 4
;; NIL
(format t "~{~a: ~a~%~}" (list 1 2 3 4))
;; 输出:
;; 1: 2
;; 3: 4
;; 这样看起来很讨厌,必须得让它在列表没元素的时候停止打印逗号:
(format t "~{~a,~}" (list 1 2 3 4 5)) ; => 1,2,3,4,5,
;;; ~^:
(format t "~{~a~^,~}" (list 1 2 3 4 5)) ; => 1,2,3,4,5
;; 配合 ~@,可以把参数当作列表处理:
(format t "~@{~a~^,~}" 1 2 3 4 5) ; => 1,2,3,4,5