Emacs:捕获段落并对每个段落采取行动

时间:2011-11-25 17:36:19

标签: emacs elisp

我经常需要使用正则表达式捕获区域中的某些段落 - 然后对每个段落执行操作。

例如,考虑恢复数字列表的问题:

1. Some text with a blank
line. I want not to have that line break
2. Some more text. Also - with
a line break.
3. I want to have a defun which
will capture each numbered entry
and then join it

我想写一个defun,它会使之前的文字像这样:

1. Some text with a blank line. I want not to have that line break
2. Some more text. Also - with a line break.
3. I want to have a defun which will capture each numbered entry and then join it

这是我现在最好的尝试:

(defun joining-lines (start end)
  (interactive "r")
  (save-restriction 
    (narrow-to-region start end)
    (goto-char (point-min))
    (while (search-forward-regexp "\\([[:digit:]]\\. \\)\\(\\[^[:digit:]\\].*?\\)" nil t)
           (replace-match "\\1\\,(replace-regexp-in-string " ;; here's a line break
" " " (match-string 2))" t nil))
   )
)

它既不起作用也不会出错。

实际上,最好有一个单独的defun来对字符串进行操作。通过这种方式,可以很容易地扩展代码以在replace-match上进行多次替换。

3 个答案:

答案 0 :(得分:4)

您的代码存在两个问题:

  1. 正则表达式中的句点与“除换行符之外的任何内容”匹配,因此您的.*?将永远不会包含换行符。
  2. \,(...) regexp替换构造仅以交互方式提供。如果问题#1已解决,则会收到错误(error "Invalid use of '\\' in replacement text")。以编程方式,您必须自己编写代码,例如:(replace-match (concat (match-string 1) (replace-regexp-in-string "\n" " " (match-string 2))))
  3. 我认为你最好不要依赖正则表达式在这里做繁重的工作。这对我有用:

    (defun massage-list (start end)
      (interactive "r")
      (save-excursion
        (save-restriction
          (narrow-to-region start end)
          (goto-char start)
          (while (progn (forward-line) (= (point) (line-beginning-position)))
            (when (not (looking-at "^[[:digit:]]+\\."))
              (delete-indentation)
              (beginning-of-line))))))
    

答案 1 :(得分:1)

尝试类似这样的代码。它不是最短的,而是直截了当的。

(defun joining-lines(start end)
  (interactive "r")
  (let ((newline-string "~~~"))
    (save-restriction 
      (narrow-to-region start end)
      (mark-whole-buffer)
      (replace-string "\n" newline-string)
      (goto-char start)
      (while (re-search-forward (concat newline-string "\\([[:digit:]]+. \\)") nil t)
        (replace-match "\n\\1" nil nil))
      (mark-whole-buffer)
      (replace-string newline-string " "))))

答案 2 :(得分:0)

以下是使用外部修改的解决方案:

(defun capturing-paragraphs (start end)
  (interactive "r")
  (save-restriction 
    (narrow-to-region start end)
    (goto-char (point-min))
    (while (search-forward-regexp "^\\(^[[:digit:]]+\\.[^[:digit:]]+$\\)" nil t) (replace-match (multiple-find-replace-in-match) t nil))))

(defun multiple-find-replace-in-match ()
  "Returns a string based on current regex match."
  (let (matchedText newText)
    (setq matchedText
      (buffer-substring-no-properties
        (match-beginning 1) (match-end 1)))
    (setq newText
      (replace-regexp-in-string "\n" "" matchedText) )
    newText))

只有在文本中没有数字时才有效。但是这个解决方案很容易扩展 - 在匹配的字符串上添加新的替换。