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