轨道
/
Common Lisp
Common Lisp
/
练习
/
前来报到
前来报到

前来报到

学习练习

简介

格式 - 基础

Common Lisp 中有一个叫作打印器的概念,它包含所有用于写出 Lisp 数据的文本表示的函数。其中一个函数是format,它让程序员可以按自己的需要格式化数据。

format以及 Lisp 打印器整体上的能力是一个很大的话题;这里将介绍使用format的基础知识。

FORMAT 函数

函数format至少接受两个实参:一个是要打印到的流,另一个是定义打印什么以及如何打印的控制字符串。

流本身是一个单独的概念,会在别处介绍。不过现在只需要知道:打印是输出到流上的,而这个实参有两个特殊值:t和nil。t表示打印到标准输出(实际上是变量*standard-output*所绑定的那个流),nil表示创建一个字符串并返回它。

注意,除非在后一种情况下把nil指定为流,否则format求值的结果总是nil。这是进行简单的字符串插值或构造的常见方式。

(format nil "hello world") ; => "hello world"
(format t "hello world")   ; => NIL (but "hello world" is printed to standard output)

格式指示符

控制字符串可以包含“格式指示符”,它们告诉format该打印什么,以及如何解释传给format的其他实参。某种意义上,控制字符串就是一个由format解释并运行的程序。所有指示符都以~开头,后面跟一个字符(例如~A、~D、~&)。字符的大小写无关紧要。

多数格式指示符只是把一个传给format的实参插入到输出中。这叫作“消耗”该实参。有些指示符不消耗实参,有些则消耗不止一个。甚至有一个指示符允许你在实参列表中来回跳转,或跳过某些实参。

基本格式

一个非常通用的格式指示符是~A。它会打印数据的“人类可读”版本。

(format nil "Value = ~a" 10)                ; => "10"
(format nil "hello ~a" "world")             ; => "hello world"
(format nil "The list is: ~A" (list 1 2 3)) ; => "The list is: (1 2 3)"

另一个有用的格式指示符是~S。它会打印数据的“机器可读”版本。如果你想能把生成的输出当作 Lisp 数据来解读,这会非常有用。对许多东西来说,它看起来和~A一样,但要注意,比如对字符串而言,输出中会包含引号(当被嵌入另一个字符串时会被转义),这样这个值就能作为字符串实参读回来。

(format nil "~s" 10)            ; => "10"
(format nil "~s" "hello world") ; => "\"hello world\""
(format nil "~s" (list 1 2 3))  ; => "(1 2 3)"

另外两个非常有用的指示符是~%和~&。前者输出一个换行符,后者输出一个“新行”。区别在于,~%总是输出一个换行符,而~&只在当前不在行首时才输出一个。这两者都不消耗实参。

(format nil "~%new~%lines") ; => "
                                  new
                                  lines"

(format nil "~&new~&lines"  ; => "new
                                  lines"

最后,~~是一个简单的指示符,会输出一个字面量~。

说明

和几乎所有有工作的人一样,Lisp 外星人 Layla 有时也需要做报告,让别人了解一些信息。他们想请你帮忙,把她为这些报告准备的数据格式化好。

1. 格式化季度数值

Layla 首先需要一个函数:format-quarter-value,它接收两个形参:日历季度和数值,并把它们格式化后用于报告。它应该求值为一个字符串。

(format-quarter-value "last" 3.14) ; => "The value last quarter: 3.14"
(format-quarter-value "this" 0) ; => "The value this quarter: 0"

2. 双季度报告

Layla 感谢你写了 format-quarter-value函数,并说它在下一个需要的函数中会非常有用。

下一份报告需要把两个季度的季度和数值分别打印在两行上。

另外,输出需要写入作为第一个实参传入的流。

例如:(format-two-quarters t "last" 3.14 "this" 0)会在标准输出上产生以下内容:


The value last quarter: 3.14
The value this quarter: 0

注意它前后的空行。

3. 人类可读与 Lisp 外星人可读

Layla 忘了告诉你,Lisp 外星人喜欢以可读作 Lisp 数据的方式来查看值。所以他们需要一个新函数,它的输出可以当作 Lisp 数据读取(同样写入指定的流):

(format-two-quarters-for-reading nil "last" 3.14 "this" 0) ; =>

"(\"The value last quarter: 3.14\" \"The value this quarter: 0\")"
通过 GitHub 编辑 链接将在新窗口或新标签页中打开
Common Lisp Exercism

准备好开始 前来报到 了吗?

注册 Exercism,借助 27 个概念92 个练习 和真人导师指导,学习并掌握 Common Lisp,全部免费。