10

In Python I'd do the following to process a file line by line:

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

Trying to look up how to do the same in elisp (with buffers instead of files), I found no obvious way.

(What I want to end up with is two ordered datastructures of lines, one with all the lines matching a regex, the other containing those that did not match.)

20

There are various ways to do it. Kaushal's way can be made a good bit more efficient, with:

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

But in Emacs it is much more customary to work on the buffer rather than on strings. So rather than extract the string and then work on it, you'd just do:

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

Also, if you want to operate on a region rather than on the whole buffer, and if your "operate" includes modifying the buffer, it's frequent to do it backwards (so that you don't get bitten by the fact that the "end" position of your region moves every time you modify the buffer):

(goto-char end)
(while (> (point) start)
  ...
  (forward-line -1))
  • Thanks for those optimization tips! Always good to learn from you. – Kaushal Modi Jan 14 '16 at 15:29
  • About the last snippet, should it be this way: (let ((start (point))) (goto-char (point-max)) (while (> (point) start) ... (forward-line -1)))? – Kaushal Modi Jan 14 '16 at 16:21
  • No, the last snippet just assumes that start and end are existing variables which delimit the region on which we want to operate. – Stefan Jan 14 '16 at 19:41
6

I don't know of any idiomatic way but I came up with this:

(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)))))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.