虽然我偶尔会在 Perl regex 中做梦,但 Common Lisp (CLisp) 的格式规范仍然让我有点困惑。我正在拍摄以下结果:
给出我想要的列表("No Match" (-2378 11 4) (-2378 11 5))
:
| No Match| -2378 11 4| -2378 11 5|
Run Code Online (Sandbox Code Playgroud)
从另一端出来。这是我得到的:
[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]>
Run Code Online (Sandbox Code Playgroud)
我很高兴我已经完成了 2/3,但情况让我有点疯狂。如果我理解正确,则会|~{~9<~a~>~2*~}
消耗列表的第一个元素 ,No Match
然后跳过其余元素。下一部分~:*
将参数指针重置回列表的开头。然后~{~}
包装器将我放入列表中。接下来,~*
跳过列表中已处理的部分。下一对~{~}
进入参数的第一个子列表。第一个子列表已正确处理。然后...错误。显然我对格式的理解有问题,但我不清楚那可能是什么。
我经常觉得 CL 的其余部分非常简单,但我真的认为我们需要CL Cookbook中的“Format Cookbook”一章至少
总而言之,这位有抱负的人需要来自更有知识的追随者的帮助。帮助!
我逐步构建了一个解决方案。由于格式字符串只有一个参数,因此我首先创建一个打印列表中每个元素的格式字符串:
CL-USER> (format t "~{|~A~}|"
'("No Match" (-2378 11 4) (-2378 11 5)))
|No Match|(-2378 11 4)|(-2378 11 5)|
Run Code Online (Sandbox Code Playgroud)
现在,在第一个元素之后,我们实际上想要迭代所有剩余的参数,我们可以使用~@{
. 我在每个元素周围添加了方括号,以便我们可以看到迭代的边界。
CL-USER> (format t "~{|~A ~@{[~A]~}~}|"
'("No Match" (-2378 11 4) (-2378 11 5)))
|No Match [(-2378 11 4)][(-2378 11 5)]|
Run Code Online (Sandbox Code Playgroud)
现在,方括号中列表中的每个元素都需要单独打印,因为字段宽度并不完全相同。~A
我们也可以用now替换最初的~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|
Run Code Online (Sandbox Code Playgroud)
现在(另一个答案也指出了这一点),使用~@
紧随其后的~{
结构可以用 替换~:@{
,这会缩短格式字符串。
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|
Run Code Online (Sandbox Code Playgroud)
最后,美学指令~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|
Run Code Online (Sandbox Code Playgroud)
这种增量方法在 Lisp 中可以非常频繁地使用,首先解决问题的一部分,然后逐步完善解决方案。与其他具有更昂贵的写入-编译-运行周期的语言不同,Lisp 的快速 REPL 使这种过程变得非常容易。
如果您要使用 做大量工作format
,那么值得浏览一下HyperSpec 中的第 22.3 节“格式化输出” 。大多数功能您可能在相当长一段时间内不会使用,但是浏览完该部分后,当您需要它们时,它们就会出现在您的脑海中。(然后你必须查阅手册,但最常被低估的一点是,你会知道手册中有一些内容,以及在哪里可以找到它。)