Justification in a format with variable number of items in a list
Asked Answered
R

1

7

So I can do this:

CL-USER> (format t "~80<~a~;~a~;~a~;~a~>~%" "hello" "how are you" "i'm fine" "no you're not")
hello              how are you              i'm fine               no you're not

It evenly spaces the 4 strings across the span of 80 as specified.

However, I want to pass a list of strings, and have it justify those instead, based on however many are in the list.

Neither of these do it:

CL-USER> (format t "~{~80<~a~;~>~}~%" '(1 2 3 4 5 6))
1
2
3
4
5
6

CL-USER> (format t "~80<~{~a~;~}~>~%" '(1 2 3 4 5 6))
; Evaluation aborted on #<SB-FORMAT:FORMAT-ERROR {126651E1}>.
; ~; not contained within either ~[...~] or ~<...~>

Is there a way to do this?

Rustice answered 10/12, 2013 at 14:54 Comment(0)
S
7

You can do this with (format stream (format nil ...)) where you generate the format control for justification using format:

CL-USER> (format nil (format nil "|~~40<~{~a~^~~;~}~~>|" '(1 2 3 4 5)))
"|1        2         3         4         5|"
CL-USER> (format nil (format nil "|~~40<~{~a~^~~;~}~~>|" '(1 2 3 4 5 6 7 8 9 10)))
"|1   2   3   4   5   6   7   8    9    10|"
CL-USER> (format nil (format nil "|~~40<~{~a~^~~;~}~~>|" '(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)))
"|1 2 3 4 5 6 7 8 9 10  11  12  13  14  15|"

If you don't want to generate the whole format control for the outer format, you can use some variant of ~? to process a string and some arguments recursively:

CL-USER> (format nil "|~@?|" (format nil "~~40<~{~a~^~~;~}~~>" '(1 2 3 4 5)))
"|1        2         3         4         5|"
CL-USER> (format nil "|~@?|" (format nil "~~40<~{~a~^~~;~}~~>" '(1 2 3 4 5 6 7 8 9 10)))
"|1   2   3   4   5   6   7   8    9    10|"
CL-USER> (format nil "|~@?|" (format nil "~~40<~{~a~^~~;~}~~>" '(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)))
"|1 2 3 4 5 6 7 8 9 10  11  12  13  14  15|"

The recursive processing with ~? only allows you to process another format control with a list of arguments; it doesn't give you a way to splice in a new format string. It appears that the text that is justified has to be present in the control string, so you'd really need a way to splice in a control string that already contains the text that you want.

Although the first of these seems simpler, there is a danger in it because you're putting the printed text into another format string, and you're not doing that in the second case. In the first case, if any of those numbers were replaced with format directives, the outer format would try to process them. In the second case, this doesn't happen. As such, I think I'd suggest the second.

Sedative answered 10/12, 2013 at 21:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.