【问题标题】:Lisp format a character a number of timesLisp 多次格式化一个字符
【发布时间】:2013-12-03 02:08:19
【问题描述】:

我正在寻找一种输出字符的方法 多次使用格式。这可能吗?有人可以填吗 在_?_ 中,这样该示例是否有效?

(let ((n 3))
  (format nil "_?_" _?_ #\* _?_ ))

应该返回

=> "***"

【问题讨论】:

  • 您可能想标记您的问题common-lispformat 的工作方式与 Common Lisp 中的类似,但 Scheme 的方言也可以实现类似的功能。 format 在 Emacs Lisp 中的工作方式不同。
  • @wvxvw 我总觉得format 问题是一种反常的混淆代码竞赛,或者是一种特殊的代码高尔夫。除了common-lisp 标签之外,我想知道是不是也应该没有stupid-format-tricks 标签? :)
  • 为什么这么严重?令人愉快的格式技巧
  • @JoshuaTaylor Google 说 Lisp 中还没有 J 解释器......可能会给你一些想法:)
  • @LarsBrinkhoff 基于术语“愚蠢的人类技巧”。我实际上有点喜欢这些问题。它们是很好的晨练。 :)

标签: format lisp common-lisp


【解决方案1】:

很高兴看到这么多解决方案:~A、~

~@{ 迭代构造提供了一个简洁的解决方案:

(format nil "~v@{~A~:*~}" 3 #\*)

【讨论】:

  • 也可以使用 ~C 代替 ~A。写一个字符比通过“打印机”写一个 Lisp 对象更简单。
  • 对,但你已经在单独的答案中提出了这一点,所以我不会更新我的。
【解决方案2】:
(format nil "~a~:*~a~:*~a~:*" #\*)
"***"

或详细说明约书亚·泰勒的回答:

(format nil "~v{~a~:*~}" 3 '(#\*))

将是这样做的一种方式。不要被format 指令中的星号弄糊涂了,它们是控制字符,而不是正在打印的字符。


然而,就效率而言,这是:

(make-string 3 :initial-element #\*)

将是实现相同效果的首选方式。

【讨论】:

  • 我还要说“就可读性而言”,这将是首选方式(当然,除了为它制作一个函数之外)。
【解决方案3】:

如果您使用~A 指令,您可以完全按照您建议的形式得到它,即,

(let ((n 3))
  (format nil "_?_" _?_ #\* _?_ ))

具有三个格式参数。然而,如果你使用~<,你实际上可以只用两个格式参数来做到这一点。如果您不需要在format 已经生成的其他字符串中使用此字符串,您也可以使用make-string 创建字符串。

使用波浪号 A (~A)

您可以打印字符并指定最小宽度和与填充字符相同的字符。例如,使用~v,,,vA 和两个参数,您可以确保打印一定数量的字符,以及填充字符是什么。

CL-USER> (let ((n 3))
           (format nil "~v,,,vA"
                   n     ; number of characters that must be printed
                   #\*   ; character to use as padding
                   #\*)) ; character to print with ~A
"***"

CL-USER> (let ((n 3))
           (format nil "~v,,,vA" n #\* #\*)) 
"***"

CL-USER> (let ((n 10))
           (format nil "~v,,,vA" n #\* #\*))
"**********"

这使用full form of ~A:

~mincol,colinc,minpad,padcharA 是 ~A 的完整形式,它允许 控制填充。字符串填充在右侧(或 如果使用了 @ 修饰符,则留下)至少具有 minpad 副本 帕查;然后将填充字符插入 colinc 字符 直到总宽度至少为 mincol 的时间。默认值为 0 mincol 和 minpad,1 表示 colinc,空格字符表示 padchar。

还有v:

可以使用 V(或 v)代替指令的前缀参数。 在这种情况下,format 将来自 args 的参数作为参数传递给 指示。参数应该是整数或字符。如果参数 V 参数使用的参数为 nil,效果就好像参数有 被省略了。 # 可以用来代替前缀参数;它 表示剩余要处理的 args 数量。使用时 在递归格式中,在 ~?或 ~{,# 前缀 参数表示剩余的格式参数的数量 递归调用。

使用小于号 (~

还有一个不太常用的格式指令,波浪号小于,用于对齐。它需要一个格式字符串并生成 s

~mincol,colinc,minpad,padchar

这证明了在字段中处理 str 所产生的文本 最小 mincol 列宽。 str 可以被分成多个段 ~;,在这种情况下,文本之间的间距是均匀分布的 段。

我们可以(ab)通过传递一个空格式字符串并仅指定宽度和填充字符来使用它:

CL-USER> (let ((n 3))
           (format nil "~v,,,v<~>"
                   n     ; width
                   #\*)) ; padding character
"***"

CL-USER> (let ((n 5))
           (format nil "~v,,,v<~>" n #\*))
"*****"

只做一个字符串

当然,除非你需要这个特殊字符串 inside 在你已经格式化的其他字符串中,否则你应该按照 wvxvw 的建议做,只使用make-string

(make-string 3 :initial-element #\*)

其他选择

format 非常灵活,正如这个答案和其他答案所指出的那样,有很多方法可以做到这一点。我试图坚持那些应该一次性完成并且不进行显式迭代的方法,但这也可以通过format 迭代来完成,正如Lars Brinkhoffwvxvw 所指出的那样。

【讨论】:

    【解决方案4】:

    和 Lars 的回答一样,但是我们用~C 写字符,而不是用~A 使用打印机:

    (format nil "~v@{~C~:*~}" 3 #\*)
    

    write-char 之类的东西写一个字符比打印一个 Lisp 对象更简单。打印机需要观察很多上下文,并且必须找到打印对象的正确方法。 OTOH,WRITE-CHAR 之类的东西只是将单个字符写入流。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-07
      • 1970-01-01
      相关资源
      最近更新 更多