是否有一种惯用的方式来读取缓冲区中的每一行以逐行处理它?


11

在Python中,我将执行以下操作来逐行处理文件:

with open(infile) as f:
    for line in f:
        process(line)

尝试查找如何在elisp中执行相同操作(使用缓冲区而不是文件),我发现没有明显的方法。

(我要结束的是两行有序的数据结构,一个数据行与正则表达式匹配,另一行包含不匹配的行。)

Answers:


23

有多种方法可以做到这一点。可以通过以下方法使Kaushal的方法更有效:

(goto-char (point-min))
(while (not (eobp))
  (let ((line (buffer-substring (point)
                                (progn (forward-line 1) (point)))))
    ...))

但是在Emacs中,更常见的是在缓冲区而不是字符串上工作。因此,您只需执行以下操作即可,而不是提取字符串然后再对其进行处理:

(goto-char (point-min))
(while (not (eobp))
  ...
  (forward-line 1))

另外,如果您要在区域上而不是整个缓冲区上进行操作,并且如果您的“操作”包括修改缓冲区,那么经常向后进行操作(这样您就不会被“结束”这一事实所困扰。每次修改缓冲区时区域的位置都会移动”:

(goto-char end)
(while (> (point) start)
  ...
  (forward-line -1))

感谢您的优化提示!向您学习总是好事。
Kaushal Modi

关于最后一个片段,应该这样(let ((start (point))) (goto-char (point-max)) (while (> (point) start) ... (forward-line -1)))吗?
Kaushal Modi

不,最后一个代码段仅假定startend是现有变量,它们界定了我们要操作的区域。
Stefan

6

我不知道任何惯用的方式,但是我想到了:

(defun my/walk-line-by-line ()
  "Process each line in the buffer one by one."
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (while (not (eobp))
      (let* ((lb (line-beginning-position))
             (le (line-end-position))
             (ln (buffer-substring-no-properties lb le)))
        (message ">> %s" ln) ; Replace this with any processing function you like
        (forward-line 1)))))

1

我认为以下内容非常实用:

(dolist (line (split-string (buffer-string) "\n")) 
  ... process line here ...
  )

编辑:这是loop替代的另一种解决方案dolist,它还根据行是否与您的正则表达式匹配来对行进行分类:

(loop for line in (split-string (buffer-string) "\n")
  if (string-match "your-regexp" line)
    collect line into matching
  else
    collect line into nonmatching
  finally return (cons matching nonmatching)
  )

例如,如果将变量设置为该函数的输出 (setq x (loop ...)),则将在其中找到所需的匹配行(car x)列表,而不匹配的行列表为(cdr x)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.