Reputation: 1576
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?
Upvotes: 1
Views: 502
Reputation: 8421
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 v
s 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.
Upvotes: 5