Join Every N Lines By A Separator in Emacs


It has been some time since I came along the idea of the w/join-lines command to join lines. After that, sometimes I found that it would be even better to join every a few lines.

Let's see the example below, suppose we've copies some data from somewhere, and now we want to yank it into an Emacs buffer and slightly modify it to be like an matrix.

That is, make it from:

11
12
13
21
22
23
31
32
33

to:

11, 12, 13
21, 22, 23
31, 32, 33

In the spirit of w/join-lines, it's not very hard to come up with the general idea, though there are some details to take care of. Here is the command:

(defvar w/join-lines--last-separator ","
  "Keep the last used separator for `w/join-lines' and
`w/join-every-n-lines', a comma by default.")

(defun w/join-every-n-lines (&optional specify-separator)
  "Join every N lines in the active region by a separator,
by default the last used.

Specify the separator by typing C-u before executing this
command.

Note: it depends on s.el."
  (interactive "P")
  (require 's)
  (unless (region-active-p)
    (error "select a region of all-lines first."))
  (let* ((n (string-to-number (read-string "N =: ")))
         (separator (if (not specify-separator)
                        w/join-lines--last-separator
                      (read-string "Separator: ")))
         (text (buffer-substring-no-properties
               (region-beginning)
               (region-end)))
         (all-lines (split-string text "\n"))
         n-lines
         result)
    (while all-lines
      (let (lines line)
        (dotimes (_ n)
          (when (setq line (pop all-lines))
            (push line lines)))
        (push (reverse lines) n-lines)))
    (setq result (mapconcat (lambda (lines)
                              (s-join separator lines))
                            (reverse n-lines) "\n"))
    (delete-region (region-beginning) (region-end))
    (insert result)
    (setq w/join-lines--last-separator separator)))
Emacs 

See also

comments powered by Disqus