问题
I need to generate a space-padded string with a variable string length. The not-so-clever solution that works involved nesting of format:
(format nil (format nil "~~~d,,a" 10) "asdf")
Now, I wanted to make it a bit more clever by using format's ~? for recursive processing. I would expect that something like this should do what I want:
(format nil "~@?" "~~~d,,a" 10 "asdf")
but what I get is just the formatting string, i.e. ~10,,a, not the padded asdf string. Perhaps I misunderstood the word 'recursive' here, but I would expect that having formed the inner format string, CL should proceed to actually use it. Am I missing something?
回答1:
Variable arguments to format directives
FORMAT allows you to use v as an argument to a directive in the control string to pop arguments from the argument list.
CL-USER> (format nil "~va" 10 "asdf")
"asdf "
There may be multiple vs used.
CL-USER> (format nil "~v,,,va" 10 #\- "asdf")
"asdf------"
Recursive processing with ~?
The recursive processing directive is meant for embedding a different "call" to FORMAT inside a control string. For example, a function to prompt for a yes or no answer might be implemented with it.
(defun y-or-n-prompt (control-string &rest args)
(format t "~&~? [y/n]: " control-string args)
;;...
)
The caller can now format a prompt with this as they would with FORMAT without having to worry about the details of what the prompt should look like to the user (adding a new line at the beginning or the [y/n]: prompt at the end).
CL-USER> (y-or-n-prompt "foo ~d bar" 12)
foo 12 bar [y/n]:
NIL
The result of ~? will not be processed by FORMAT, so it cannot be used to build a control string. In general, building control strings at run time is a bad idea, because it's error prone (for example, you must escape any unwanted tildes in the string) and prevents the implementation from processing the control string at compile time.
来源:https://stackoverflow.com/questions/48868555/in-common-lisp-format-how-does-recursive-formatting-work