20.2 输入流

大部分用于读取文本的 Lisp 函数都会接受一个 输入流(input stream) 作为参数。 输入流指定从何处、以何种方式获取待读取的字符。 输入流可以是以下类型:

buffer

从缓冲区 buffer 中读取字符,起始位置为光标后一位。 随着字符被读取,光标会向后移动。

marker

从标记 marker 所在的缓冲区读取字符,起始位置为标记后一位。 随着字符被读取,标记位置会向后移动。 当流是标记时,缓冲区中的光标位置不产生影响。

string

从字符串 string 中获取输入字符,从字符串第一个字符开始,按需读取。

function

输入字符由函数 function 生成,该函数必须支持两种调用方式:

  • 无参数调用时,返回下一个字符。
  • 带一个参数(总是一个字符)调用时, 函数应保存该参数,并在下一次调用时返回它。 这被称为 回退字符(unreading the character); 通常发生在 Lisp 读取器多读了一个字符并希望将其放回时。 这种情况下函数 funtion 返回什么值并不重要。
t

t 作为流表示从迷你缓冲区读取输入。 实际上,迷你缓冲区会被激活一次,用户输入的文本会被构造成字符串并作为输入流使用。 如果 Emacs 以批处理模式运行(see Batch Mode),则使用标准输入而非迷你缓冲区。 例如:

(message "%s" (read t))

在批处理模式下会从标准输入读取一个 Lisp 表达式,并将结果打印到标准输出。

nil

nil 作为输入流表示使用变量 standard-input 的值; 该值是 默认输入流(default input stream),必须是一个非nil 的输入流。

symbol

符号作为输入流等价于使用该符号的函数定义(如果存在)。

下面是从缓冲区流中读取的例子,展示读取前后光标的位置:

---------- Buffer: foo ----------
This∗ is the contents of foo.
---------- Buffer: foo ----------

(read (get-buffer "foo"))
     ⇒ is
(read (get-buffer "foo"))
     ⇒ the

---------- Buffer: foo ----------
This is the∗ contents of foo.
---------- Buffer: foo ----------

注意第一次读取会跳过一个空格。读取会自动跳过有效文本前的任意空白。

下面是从标记流读取的例子,标记初始位于缓冲区开头。 读取到的值是符号 This


---------- Buffer: foo ----------
This is the contents of foo.
---------- Buffer: foo ----------

(setq m (set-marker (make-marker) 1 (get-buffer "foo")))
     ⇒ #<marker at 1 in foo>
(read m)
     ⇒ This
m
     ⇒ #<marker at 5 in foo>   ;; Before the first space.

下面从字符串内容中读取:

(read "(When in) the course")
     ⇒ (When in)

下面的例子从迷你缓冲区读取。提示语为:‘Lisp expression: 。 (使用流 t 读取时总是使用该提示。) 提示后的内容为用户输入。

(read t)
     ⇒ 23
---------- Buffer: Minibuffer ----------
Lisp expression: 23 RET
---------- Buffer: Minibuffer ----------

最后是一个函数流的例子,函数名为 useless-stream。 在使用该流之前,我们先将变量 useless-list 初始化为一个字符列表。 之后每次调用 useless-stream 会从列表中取下一个字符, 或通过将字符添加到列表头部来回退字符。

(setq useless-list (append "XY()" nil))
     ⇒ (88 89 40 41)

(defun useless-stream (&optional unread)
  (if unread
      (setq useless-list (cons unread useless-list))
    (prog1 (car useless-list)
           (setq useless-list (cdr useless-list)))))
     ⇒ useless-stream

现在用构造出的流进行读取:

(read 'useless-stream)
     ⇒ XY

useless-list
     ⇒ (40 41)

注意左右括号仍然留在列表中。 Lisp 读取器遇到左括号后判定输入结束,并将其回退。 此时再次从该流读取会读到 ‘()’ 并返回 nil


emacs

Emacs

org-mode

Orgmode

Donations

打赏

Copyright

© 2025 Jasper Hsu

Creative Commons

Creative Commons

Attribute

Attribute

Noncommercial

Noncommercial

Share Alike

Share Alike