Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Justification in a format with variable number of items in a list

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?

like image 908
johnbakers Avatar asked Dec 10 '13 14:12

johnbakers


1 Answers

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.

like image 184
Joshua Taylor Avatar answered Sep 18 '22 23:09

Joshua Taylor