Common Lisp format 遍历子列表时如何省略末尾逗号?
数据小许
结论
把分隔符前的 ~^ 改为 ~:^。在 ~:{...~} 中,无参数的 ~:^ 会检查当前子列表是否为最后一个。如果是,就结束整个迭代,跳过后面的逗号。
为什么原来的写法会省略所有分隔逗号?
~:{...~} 每次取一个子列表,为迭代体提供参数。原代码中的两个 ~d 用完了当前子列表的两个元素。接着,~^ 检查到当前迭代没有剩余参数,便结束这一次迭代,跳过逗号,再处理下一个子列表。每次迭代都是如此,因此所有分隔逗号都没有输出。
~:^ 检查的则是当前子列表是否为最后一个。这一行为见 Common Lisp HyperSpec §22.3.9.2。
修改后的代码
保持 ~:{...~} 和两个 ~d 不变,把逗号前的 ~^ 换成 ~:^:
(format nil "[~:{[~d,~d]~:^,~}]" '((1 2) (3 4)))
;; => "[[1,2],[3,4]]"
处理 (1 2) 时,后面还有子列表,因此输出逗号;处理 (3 4) 时,它是最后一个子列表,便跳过逗号并结束迭代。~} 后面的外层右方括号仍会输出。
外层列表只有一个子列表或为空时,同样适用,预期结果分别如下:
(format nil "[~:{[~d,~d]~:^,~}]" '((1 2)))
;; => "[[1,2]]"
(format nil "[~:{[~d,~d]~:^,~}]" '())
;; => "[]"
注意事项
- 将
~:^放在需要省略的分隔符之前;写在逗号后面无法撤回已经输出的字符。 - 示例按每个子列表提供两个整数来编写,两个
~d分别读取它们。 ~:^的用法有上下文限制:它要终止的迭代必须是~:{...~}或~:@{...~},不能直接替换普通~{...~}中的~^。
备注:内容仅供参考。
