虽然我偶尔会在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; 章节食谱至少。
总之,这个有抱负的人需要一位知识渊博的追随者提供帮助。帮助!
答案 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}}和@
修饰符来处理剩余的列表,而不是向前和向后跳过:
~{