Lisp格式字符串,用于元素和子列表的列表

时间:2013-06-16 18:12:49

标签: format lisp

虽然我偶尔会在Perl正则表达式中做梦,但Common Lisp(CLisp)的格式规范仍然让我感到有些困惑。我正在拍摄以下结果:

给出我想要的列表("No Match" (-2378 11 4) (-2378 11 5))

| No Match| -2378 11  4| -2378 11  5|

走出另一端。以下是我得到的内容:

[685]> (fss sd)

("No Match" (-2378 11 4) (-2378 11 5))
[686]> (format t "|~{~9<~a~>~2*~}~:*~{~*~{|~6d~3d~3d~}~}|" (fss sd))
| No Match| -2378 11  4
*** - There are not enough arguments left for this format directive.
      Current point in control string:
        "|~{~9<~a~>~2*~}~:*~{~*~{|~6d~3d~3d~}~}|"
                                           |
The following restarts are available:
ABORT          :R1      Abort main loop
Break 1 [687]> :R1

[688]>

我很高兴我在那里的方式,但情况让我有点疯狂。如果我理解正确,|~{~9<~a~>~2*~}会使用列表的第一个元素No Match,然后跳过其余元素。下一部分~:*将参数指针重置回列表的开头。然后~{~}包装器将我放入列表中。接下来,~*会跳过列表中已处理的部分。下一对~{~}进入参数的第一个子列表。第一个子列表处理正确。然后...错误。很明显,我对格式的理解有些不妥,但我不清楚这可能是什么。

我经常觉得CL的其余部分非常直接,但我认为我们需要 CL中的&#39;格式指南&#39; 章节食谱至少。

总之,这个有抱负的人需要一位知识渊博的追随者提供帮助。帮助!

2 个答案:

答案 0 :(得分:3)

我逐渐构建了一个解决方案。由于格式字符串只有一个参数,因此我首先创建了一个格式字符串,用于打印列表的每个元素:

CL-USER> (format t "~{|~A~}|"
                 '("No Match" (-2378 11 4) (-2378 11 5)))
|No Match|(-2378 11 4)|(-2378 11 5)|

现在,在第一个元素之后,我们实际上想要迭代所有剩余的参数,我们可以使用~@{。我在每个元素周围添加了方括号,以便我们可以看到迭代的边界。

CL-USER> (format t "~{|~A ~@{[~A]~}~}|"
                 '("No Match" (-2378 11 4) (-2378 11 5)))
|No Match [(-2378 11 4)][(-2378 11 5)]|

现在,方括号中的元素中的每个元素都需要单独打印,因为字段宽度并不完全相同。我们现在也可以用~A替换最初的~9<~A~>

CL-USER> (format t "~{|~9<~A~>~@{~{|~6d~3d~3d~}~}~}|"
                 '("No Match" (-2378 11 4) (-2378 11 5)))
| No Match| -2378 11  4| -2378 11  5|

现在(在另一个答案中也指出了这一点),~@后面紧跟~{的使用是一个可被~:@{取代的构造,缩短了格式字符串。

CL-USER> (format t "~{|~9<~A~>~:@{|~6d~3d~3d~}~}|"
                 '("No Match" (-2378 11 4) (-2378 11 5)))
| No Match| -2378 11  4| -2378 11  5|

最后,aesthetic directive, ~A可用于指定字段宽度。 ~mincolA在右侧放置空格,但~mincol@A将它们放在左侧,因此不需要使用~<~9<~A~>变为~9@A

CL-USER> (format t "~{|~9@A~:@{|~6d~3d~3d~}~}|"
                 '("No Match" (-2378 11 4) (-2378 11 5)))
| No Match| -2378 11  4| -2378 11  5|

这种增量方法可以在Lisp中非常频繁地用于首先解决部分问题,然后逐步优化解决方案。与其他编写运行周期更昂贵的语言不同,Lisp的快速REPL使这种过程非常简单。

如果您打算使用format做大量工作,则值得浏览HyperSpec中的22.3 Formatted Output部分。你可能在很长一段时间内都不会使用的大多数功能,但是在浏览完这一部分时,它们会在你需要它们的时候出现在你的脑海中。 (那么你将不得不参考手册,但是经常被低估的一点是你会知道手册中有什么东西,以及在哪里寻找它。)

答案 1 :(得分:1)

使用第三个~{,您将进入第一个子列表的逐元素打印。每次迭代都会消耗子列表的三个元素,因此在单次传递后完成。然后,退出该循环,下一个更高的循环进入下一次迭代。它会跳过外部列表中的另一个元素(第二个子列表),但之后没有任何参数可用于再次进入内部循环。

您可以简单地同时使用:的{​​{1}}和@修饰符来处理剩余的列表,而不是向前和向后跳过:

~{