CL 格式秘诀:将 nil 作为值处理

CL Format recipe: Dealing with nil as a value

我一直在寻找格式化方法,但我无法完全找到我要找的东西...

(format nil CONTROL-STRING day name num-apples)

假设我不想改变上面形式的参数,只是CONTROL-STRING.

daynum-apples 将始终为非零,但 name 可能为零。

name为零时,我希望输出看起来像

"Today is Monday. Hello, you have 3 apples."

但是当 name 被定义时,我希望它看起来像

"Today is Monday. Hello Adam, you have 3 apples."

所以控制字符串需要查看name,在非nil情况下使用它,在nil情况下不使用它,但在两种情况下都消耗它。

也许可以通过消耗 nil 并将其打印为 "" 来完成?如果是这样我不知道该怎么做。

您链接到的问题 Lisp format directive that interprets nil argument to empty string instead of "NIL" 确实包含一个说明如何执行此操作的答案,但未引用任何文档。由于您要生成英文文本,因此您可能还需要考虑其他一些选项。

首先,使用~@[consequent~],你可以处理consequent格式指令,只要参数是非零,并且 ~@[ 的参数未被消耗,因此它仍然可用。一般来说, 22.3.7.2 Tilde Left-Bracket: Conditional Expression 描述了很多选项,但是关于 ~@[ 它说:

~@[consequent~] tests the argument. If it is true, then the argument is not used up by the ~[ command but remains as the next one to be processed, and the one clause consequent is processed. If the arg is false, then the argument is used up, and the clause is not processed. The clause therefore should normally use exactly one argument, and may expect it to be non-nil.

您可以按如下方式使用它:

(defun test (day name n-apples)
  (format nil "Today is ~a. Hello~@[ ~a~], you have ~a apples."
          day name n-apples))

CL-USER> (test 'monday 'adam 2)
"Today is MONDAY. Hello ADAM, you have 2 apples."
CL-USER> (test 'tuesday nil 42)
"Today is TUESDAY. Hello, you have 42 apples."

为了使它更加稳健,您应该考虑使用 ~p for pluralization,这样您就可以得到“1 个苹果”和“3 个苹果s”。

(defun test (day name n-apples)
  (format nil "Today is ~a. Hello~@[ ~a~], you have ~a apple~:P."
          day name n-apples))

CL-USER> (test 'monday 'john 2)
"Today is MONDAY. Hello JOHN, you have 2 apples."
CL-USER> (test 'tuesday 'john 1)
"Today is TUESDAY. Hello JOHN, you have 1 apple."
CL-USER> (test 'wednesday nil 0)
"Today is WEDNESDAY. Hello, you have 0 apples."

最后,由于您要生成文本,您可能会喜欢一些大小写规范化(例如,打印首字母大写的专有名词),并在文本中写入数字:

(defun test (day name n-apples)
  (format nil "Today is ~:(~a~). Hello~@[ ~:(~a~)~], you have ~r apple~:P."
          day name n-apples))
CL-USER> (list
          (test 'monday 'adam 4)
          (test 'tuesday 'john 1)
          (test 'wednesday 'mary\ sue 42)
          (test 'thursday 'jim-bob 0))
("Today is Monday. Hello Adam, you have four apples."
 "Today is Tuesday. Hello John, you have one apple."
 "Today is Wednesday. Hello Mary Sue, you have forty-two apples."
 "Today is Thursday. Hello Jim-Bob, you have zero apples.")