EMACS Lisp 程序员如何读取非编辑目的的文本文件?

How do EMACS Lisp programmers read text files for non-editing purposes?

当 EMACS Lisp 程序员想要编写大致相当于...的东西时,他们会做什么...

for line in open("foo.txt", "r", encoding="utf-8").readlines():
    ...(split on ws and call a fn, or whatever)...

..?

当我查看 EMACS lisp 帮助时,我看到了关于将文件打开到文本编辑缓冲区中的函数——这与我想要的不完全一样。我想我可以编写函数来访问文件的行,但如果我这样做了,我不希望用户看到它,此外,从文本处理的角度来看,它似乎效率不高。

  1. 是的,那你想做的:访问缓冲区中的文件,并对缓冲区中的文本进行操作。

  2. 不需要显示缓冲区,也就是说,用户不需要看到它。

  3. 关于效率:在缓冲区中操作文本通常是操作文本的有效方式。


您可以通过多种方式访问​​缓冲区中的文件。您可能希望为此使用现有的文件缓冲区,具体取决于用例。也就是说,如果文件在 Emacs 中已经是 "open",那么您可能想要使用它的缓冲区。

或者您可能想要忽略任何现有的文件缓冲区,以获取一个已经 "open" 的文件,并将文件重新读入新的缓冲区。为此,正如@Sean 提到的,您可以将 insert-file-contents 与您创建的缓冲区一起使用。您可以使用 with-temp-buffergenerate-new-buffer 创建缓冲区,同样取决于您 want/need 使用它做什么。

如果你确实想重用一个已经在访问文件的缓冲区,你可以测试它是否在内存中被修改,它是否被缩小等等,并做任何适合你的用例的事情。您可以使用函数 find-buffer-visiting.

检查是否已经有一个缓冲区访问文件(使用任何 path/file 名称)

要访问文件,利用正在访问它的任何现有缓冲区,您可以使用 find-file-noselect。该函数 returns 访问文件的缓冲区,因此您可以将该缓冲区作为第一个参数传递给 with-current-buffer。这是一个简单的例子。

(with-current-buffer (let ((enable-local-variables  ())) (find-file-noselect file))
  ;; Do some stuff with the text in the buffer.
  ;; Optionally save the buffer back to the file.
  )

enable-local-variablesnil 的绑定是一个小优化,适用于您不需要为缓冲区局部变量操心的常见情况。)

我觉得比较直接的翻译原文Python代码如下:

(with-temp-buffer
  (insert-file-contents "foo.txt")
  (while (search-forward-regexp "\(.*\)\n?" nil t)
    ; do something with this line in (match-string 1)
    ))

我认为 with-temp-buffer/insert-file-contents 通常比 with-current-buffer/find-file-noselect 更可取,因为前者保证您正在使用整个的全新副本文件内容。对于后一种构造,如果您碰巧已经有一个访问目标文件的缓冲区,那么该缓冲区将由 find-file-noselect 返回,因此如果该缓冲区已缩小,您将只能看到文件的那一部分处理它。

请记住,而不是逐行处理文件可能更方便。例如,这是一个表达式 returns 文件中所有连续数字序列的列表:

(with-temp-buffer
  (insert-file-contents "foo.txt")
  (loop while (search-forward-regexp "[0-9]+" nil t)
        collect (match-string 0)))

(require 'cl)先引入loop宏。