C.2.2 构造纵轴标注元素

打印纵轴时,我们希望每隔五行插入类似 ‘5 - 和 ‘10 -  这样的字符串。 此外,我们希望数字和短横线对齐,因此较短的数字需要在前面补空格。如果部分字符串使用两位数,那么一位数的字符串必须在数字前补一个空格。

要获取数字的长度,需要使用 length 函数。但 length 只能用于字符串,不能直接用于数字。因此必须先将数字转换为字符串,这可以通过 number-to-string 函数实现。例如:

(length (number-to-string 35))
     ⇒ 2

(length (number-to-string 100))
     ⇒ 3

number-to-string 也叫作 int-to-string;你会在不同资料中看到这个别名。)

此外,每个标注中的数字后面都会跟着类似 ‘ -  的字符串,我们称之为 Y-axis-tic 刻度标记。该变量使用 defvar 定义:

(defvar Y-axis-tic " - "
   "纵轴标注中跟在数字后的字符串。")

纵轴标注的总长度为刻度标记长度与图表顶端数字长度之和。

(length (concat (number-to-string height) Y-axis-tic)))

该值会由 print-graph 函数在其变量列表中计算为 full-Y-label-width 并传递使用。(注意我们最初提出变量列表时并未想到包含它。)

要构造完整的纵轴标注,需要将数字与刻度标记拼接;根据数字长度,前面可能带有一个或多个空格。一个标注由三部分组成:(可选的)前导空格、数字、刻度标记。函数接收当前行对应的数字,以及顶端行宽度(由 print-graph 只计算一次)作为参数。

(defun Y-axis-element (number full-Y-label-width)
  "构造带 NUMBER 数字的标注元素。
一个带编号的元素形如 `  5 - ',
并根据需要填充空格,使其与最大数字的标注对齐。"
  (let* ((leading-spaces
         (- full-Y-label-width
            (length
             (concat (number-to-string number)
                     Y-axis-tic)))))
    (concat
     (make-string leading-spaces ? )
     (number-to-string number)
     Y-axis-tic)))

Y-axis-element 函数将前导空格(如有)、转为字符串的数字以及刻度标记拼接在一起。

为计算标注需要多少前导空格,函数用目标标注宽度减去实际标注长度——即数字长度加上刻度标记长度。

空格使用 make-string 函数插入。该函数接收两个参数:第一个指定字符串长度,第二个以特殊格式指定要插入的字符符号。格式为问号后跟空格,即 ‘? ’。关于字符语法的说明,参见 See Character Type in The GNU Emacs Lisp Reference Manual。(当然,你也可以把空格换成其他字符……你知道该怎么做。)

拼接表达式中使用了 number-to-string 函数,将数字转为字符串后与前导空格和刻度标记拼接。