Next: , Previous: , Up: Controlled Formatting   [Contents][Index]


6.4.4.2 Iteration Directive

~{...~}

This directive tells FORMAT to iterate over the elements of a list or over the implicit list of the format arguments. The text between the two markers is processed as a control string, which draws its arguments from the list consumed by the ‘~{’ directive. FORMAT will repeatedly process this control string for as long as the list being iterated over has elements left.

~{...~^...~}

Within the body of a ‘~{’ directive, the ‘~^’ causes the iteration to stop immediately, without processing the rest of the control string, when no elements remain in the list. Thus, to avoid printing the comma and space after the last element of a list, you can precede them with a ‘~^’.

(format nil "~{~a~^, ~}" (list 1 2 3)) ==> "1, 2, 3"
~@{...~}

With an at-sign modifier, ‘~@{’ processes the remaining format arguments as a list.

(format nil "~@{~a~^, ~}" 1 2 3) ==> "1, 2, 3"
~{...~#[...~]...~}

Within the body of a ‘~{...~}’, the special prefix parameter ‘#’ refers to the number of items remaining to be processed in the list rather than the number of remaining format arguments. You can use that, along with the ‘~[’ directive, to print a comma-separated list with an "and" before the last item like this:

(format nil "~{~a~#[~;, and ~:;, ~]~}" (list 1 2 3)) ==> "1, 2, and 3"

However, that doesn’t really work right if the list is two items long because it adds an extra comma.

~{...~@{...~}...~}

The following takes advantage of the behavior of ‘~@{’ when nested inside another ‘~{’ or ‘~@{’ directive–it iterates over whatever items remain in the list being iterated over by the outer ‘~{’. You can combine that with a ‘~#[’ directive to make the following control string for formatting lists according to English grammar:

(defparameter *english-list*
   "~{~#[~;~a~;~a and ~a~:;~@{~a~#[~;, and ~:;, ~]~}~]~}")
<empty>

If you wanted to print something special such as ‘<empty>’ when the list was empty, you have a couple ways to do it. Perhaps the easiest is to put the text you want into the first (zeroth) clause of the outer ‘~#[’ and then add a colon modifier to the closing ‘~}’ of the outer iteration–the colon forces the iteration to be run at least once, even if the list is empty, at which point FORMAT processes the zeroth clause of the conditional directive.

(defparameter *english-list*
   "~{~#[<empty>~;~a~;~a and ~a~:;~@{~a~#[~;, and ~:;, ~]~}~]~:}")
Additional ‘~{

The ‘~{’ directive provides even more variations with different combinations of prefix parameters and modifiers. You can use an integer prefix parameter to limit the maximum number of iterations and that, with a colon modifier, each element of the list (either an actual list or the list constructed by the ‘~@{’ directive) must itself be a list whose elements will then be used as arguments to the control string in the ‘~:{...~}’ directive.


Next: Jump Directive, Previous: Conditional Directive, Up: Controlled Formatting   [Contents][Index]