“就地”区域中的重复行

时间:2013-08-20 09:37:58

标签: emacs elisp

我正在尝试编写一个elisp函数,该函数获取当前区域中的所有(非空)行并复制这些行就地。我给你举个例子:

此输入:

  

线路1
  2号线
  第3行

成为

  

线路1
  线路1
  2号线
  2号线
  3号线
  第3行

如果有空行,它们将保留在原位,不应重复。如果编码了以下功能:

(defun duplicate-lines-in-region (beg end)
  "Duplicates the lines in the current region \"in-place\"."
  (interactive "r")
  (if (use-region-p)
      (let* ((text (buffer-substring-no-properties (region-beginning) (region-end)))
             (lines (split-string text "\n" t))
             (num-lines (length lines))
             (current-line 0)
             (end-pos 0))
        (save-excursion
          (goto-char (region-beginning))
          (while (< current-line num-lines)
            (end-of-line)
            (insert "\n")
            (insert (nth current-line lines))
            (next-line)
            (setq current-line (+ current-line 1))
            (setq end-pos (point))))
        (goto-char end-pos))
    (error "No active region!")))

但是,此函数有一些(至少两个)错误:

  1. 不会忽略空行,而是完全破坏输出(行插入错误的位置)。
  2. 插入的第一行总是插入错误的缩进(在第0列),所有其他行都插入到右缩进处。
  3. 我有点坚持将功能推进到更有用的状态。另外,我非常怀疑我的方法特别有效/写得很好......也许一些elisp-guru知道一种更简单的方法,可以用来单独处理一个区域中的每一行......

1 个答案:

答案 0 :(得分:3)

这可能是作弊,但您可以使用正则表达式替换来匹配非空行并将其替换为捕获的行和副本。使用 M-x replace-regexp 突出显示的区域,以及以下参数:

  • 替换正则表达式:\(.+\)$
  • 使用:\&^J\&

请注意,在上文中,^J表示换行符/引用的回车键, C-q C-j

要将其转换为elisp,您只需要确保转义反斜杠和括号:

(defun duplicate-lines-in-region (beg end)
  (interactive "*r")
  (replace-regexp "\\(.+\\)$" "\\&\n\\&" nil beg end))