以列表中具有可变数量的项目的格式进行对齐

时间:2013-12-10 14:54:20

标签: lisp common-lisp

所以我可以这样做:

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

按指定的方式在4跨度上均匀分隔4个字符串。

但是,我希望传递一个字符串列表,并根据列表中的许多字符串来确定它们的合理性。

这些都没有:

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 ~<...~>

有办法做到这一点吗?

1 个答案:

答案 0 :(得分:7)

您可以使用(format stream (format nil ...))执行此操作,您可以使用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|"

如果您不想为外部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|"

使用~?的递归处理只允许您使用参数列表处理另一个格式控件;它没有给你一种拼接新格式字符串的方法。似乎被证明的文本必须存在于控制字符串中,因此您真的需要一种方法来拼接已包含所需文本的控件字符串。

虽然其中第一个似乎更简单,但它存在危险因为你将打印的文本放入另一个格式字符串中,而你在第二种情况下没有这样做。在第一种情况下,如果这些数字中的任何一个被格式指令替换,外部格式将尝试处理它们。在第二种情况下,这不会发生。因此,我想我会建议第二个。