formatってすげええええぇぇぇぇ

久々のLispの話題。 Common Lispのformatミニ言語の凄さに驚愕する。

SLIMEで使えるformatのcheat sheetってあるかな??

(format nil "~{~a~^, ~}" '(1 2 3)) ; => "1, 2, 3"

Floating numbers
(format nil "~$" pi)            ; => "3.14"
(format nil "~@$" pi)           ; => "+3.14"
(format nil "~5$" pi)           ; => "3.14159"
(format nil "~v$" 3 pi)         ; => "3.142"
(format nil "~$" pi)            ; => "3.14"
(format nil "~2,4$" pi)           ; => "0003.14"
(format nil "~2,4@$" pi)          ; => "+0003.14"
(format nil "~#$" pi)             ; => "3.1"
(format nil "~,5f" pi)         ; => "3.142"
(format nil "~f" pi)            ; => "3.141592653589793"
(format nil "~,4f" pi)          ; => "3.1416"
(format nil "~e" pi)            ; => "3.141592653589793d+0"
(format nil "~@e" pi)           ; => "+3.141592653589793d+0"
(format nil "~,4e" pi)          ; => "3.1416d+0"

Integers
(format nil "~d" 1000000)       ; => "1000000"
(format nil "~:d" 1000000)      ; => "1,000,000"
(format nil "~@d" 1000000)      ; => "+1000000"
(format nil "~:@d" 1000000)     ; => "+1,000,000"
(format nil "~@:d" 1000000)     ; => "+1,000,000"
(format nil "~12d" 1000000)     ; => "     1000000"
(format nil "~12,'0d" 1000000)  ; => "000001000000"
(format nil "~12,'Xd" 1000000)  ; => "XXXXX1000000"
(format nil "~4,'0d-~2,'0d-~2,'0d" 2005 6 10) ; => "2005-06-10"
(format nil "~:d" 100000000)                  ; => "100,000,000"
3番目のパラメータは桁の間に入れる文字、4番目は入れる間隔
(format nil "~,,'.,4:d" 100000000)            ; => "1.0000.0000"
日本人には4桁ごとにコンマを入れると読みやすいよね
(format nil "~,,,4:d" 100000000)              ; => "1,0000,0000"
(format nil "~d = 0x~x, 0~o, 0b~b" 255 255 255 255) ; => "255 = 0xFF, 0377, 0b11111111"
(format nil "~r" 1234)                              ; => "one thousand two hundred thirty-four"
(format nil "~:r" 1234)                             ; => "one thousand two hundred thirty-fourth"
Roman numeral
(format nil "~@r" 1234)                             ; => "MCCXXXIV"
old-style Roman numeral
(format nil "~:@r" 1234)                            ; => "MCCXXXIIII"

plural (s)
(format nil "file~p" 1)         ; => "file"
(format nil "file~p" 10)        ; => "files"
(format nil "file~p" 0)         ; => "files"
ありゃ?不規則変化には対応していない。
(format nil "child~p" 10)       ; => "childs"
直前のdirectiveにかかる
(format nil "~r file~:p" 10)    ; => "ten files"
plural (y/ies)
(format nil "~r famil~:@p" 10)  ; => "ten families"



(format nil "The value is: ~a" 10) ; => "The value is: 10"
(format nil "The value is: ~a" "foo") ; => "The value is: foo"
(format nil "The value is: ~a" (list 1 2 3)) ; => "The value is: (1 2 3)"

(format nil "The value is: ~s" "foo") ; => "The value is: \"foo\""

(char-code (elt (format nil "~%") 0)) ; => 10
~% newline, ~& fresh line
(list (format nil "~~") (format nil "~10~")) ; => ("~" "~~~~~~~~~~")

~:c スペースなどを言葉で表記
~@c S式表記
(format nil "~c/~:c/~@c/~S" #\a #\a #\a #\a)                 ; => "a/a/#\\a/#\\a"
(format nil "~c/~:c/~@c/~S" #\Space #\Space #\Space #\Space) ; => " /Space/#\\ /#\\ "
~:@c for lisp machines
(format nil "~:@c" (code-char 0))                            ; => "Nul"

downcase
(format nil "~(~a~)" "tHe Quick BROWN foX")   ==> "the quick brown fox"
capitalize
(format nil "~@(~a~)" "tHe Quick BROWN foX")  ==> "The quick brown fox"
capitalize words
(format nil "~:(~a~)" "tHe Quick BROWN foX")  ==> "The Quick Brown Fox"
upcase
(format nil "~:@(~a~)" "tHe Quick BROWN foX") ==> "THE QUICK BROWN FOX"

~[ ~] conditional formatting
(format nil "~[cero~;uno~;dos~]" 0) ; => "cero"
(format nil "~[cero~;uno~;dos~]" 1) ; => "uno"
(format nil "~[cero~;uno~;dos~]" 2) ; => "dos"
(format nil "~[cero~;uno~;dos~]" 3) ; => ""
                  0    1    2
~:; default clause
(format nil "~[cero~;uno~;dos~:;mucho~]" 3) ; => "mucho"
(format nil "~[cero~;uno~;dos~:;mucho~]" 100) ; => "mucho"
                  0    1    2    else

a prefix parameter of # will be evaluated as the number of remaining format arguments.
(defparameter *list-etc*
  "~#[NONE~;~a~;~a and ~a~:;~a, ~a~]~#[~; and ~a~:;, ~a, etc~].")
         0   1          2      else    0        1       else
(format nil *list-etc*)         ; => "NONE."
(format nil *list-etc* 'a)      ; => "A."
(format nil *list-etc* 'a 'b)   ; => "A and B."
(format nil *list-etc* 'a 'b 'c) ; => "A, B and C."
(format nil *list-etc* 'a 'b 'c 'd) ; => "A, B, C, etc."
(format nil *list-etc* 'a 'b 'c 'd 'e) ; => "A, B, C, etc."

~:[nil~;otherwise~]
(let ((test-result nil)) (format nil "~:[FAIL~;pass~]" test-result)) ; => "FAIL"
(let ((test-result 999)) (format nil "~:[FAIL~;pass~]" test-result)) ; => "pass"

~@[if TRUE~]
(format nil "~@[x = ~a ~]~@[y = ~a~]" 10 20) ; => "x = 10 y = 20"
(format nil "~@[x = ~a ~]~@[y = ~a~]" 10 nil) ; => "x = 10 "
(format nil "~@[x = ~a ~]~@[y = ~a~]" nil 20) ; => "y = 20"
(format nil "~@[x = ~a ~]~@[y = ~a~]" nil nil) ; => ""

~{ ~} iteration
(format nil "~{~a, ~}" (list 1 2 3)) ; => "1, 2, 3, "
~^ stop iteration on last element
(format nil "~{~a~^, ~}" (list 1 2 3)) ; => "1, 2, 3"
~@{ ~}
(format nil "~@{~a~^, ~}" 1 2 3)       ; => "1, 2, 3"

~{ ~} 中の#はリストの残り要素を参照する
(format nil "~{~a~#[~;, and ~:;, ~]~}" (list 1 2 3)) ; => "1, 2, and 3"
(format nil "~{~a~#[~;, and ~:;, ~]~}" (list 1 2))   ; => "1, and 2"

(defparameter *english-list*
  "~{~#[~;~a~;~a and ~a~:;~@{~a~#[~;, and ~:;, ~]~}~]~}")
        0  1          2   3+
(format nil *english-list* '())  ; => ""
(format nil *english-list* '(1)) ; => "1"
(format nil *english-list* '(1 2)) ; => "1 and 2"
(format nil *english-list* '(1 2 3)) ; => "1, 2, and 3"
(format nil *english-list* '(1 2 3 4)) ; => "1, 2, 3, and 4"

~: do iteration at least once
(defparameter *english-list*
  "~{~#[<empty>~;~a~;~a and ~a~:;~@{~a~#[~;, and ~:;, ~]~}~]~:}")
(format nil *english-list* '()) ; => "<empty>"
(format nil *english-list* '(1 2 3 4)) ; => "1, 2, 3, and 4"

~* skip an argument
(format nil "~a, ~*~a" 1 2 3)   ; => "1, 3"
~:* reuse an argument
(format nil "~r ~:*(~d)" 1)     ; => "one (1)"
(format nil "I saw ~r el~:*~[ves~;f~:;ves~]." 0) ; => "I saw zero elves."
(format nil "I saw ~r el~:*~[ves~;f~:;ves~]." 1) ; => "I saw one elf."
(format nil "I saw ~r el~:*~[ves~;f~:;ves~]." 2) ; => "I saw two elves."
(format nil "I saw ~[no~:;~:*~r~] el~:*~[ves~;f~:;ves~]." 0) ; => "I saw no elves."
~{の中では~*や~:*はリストの要素を前後する。
(format nil "~{~s~*~^ ~}" '(:a 10 :b 20))                    ; => ":A :B"

~2* 2つ飛ばす
(format nil "~a~2*~a" 1 2 3 4)  ; => "14"
~2:* 2つ前
(format nil "~a~a~a~a~2:*~a" 1 2 3 4) ; => "12343"
~2@* 2番目(0-origin)
(format nil "~a~2@*~a" 1 2 3 4) ; => "13"