删除 Emacs 中的封闭文本

Removing enclosed text in Emacs

我想删除特殊字符之间的 封闭文本 ,例如:["{'<( 等 .. 这样我就可以删除像 "this is a very ... long text" 这样的文本简单的键盘快捷键。我正在寻找一些已经存在的模式来执行类似的操作但我没有找到任何所以我创建了一些在大多数情况下都表现良好的 lisp 代码,但是它在所有情况下都无法正常工作。例如,如果我有以下文本条目,我将光标放在“^”位置,然后我想删除所有包含在“中的文本,但它不起作用:

"aaaaa ] > [more text] aaaaa"
-------------- ^

我的 lisp 代码如下:

;; returns the enclosing character for the character "c"
(defun get-enc-char (c) (cond
                         ((string= c "(") ")")
                         ((string= c "[") "]")
                         ((string= c "{") "}")
                         ((string= c ">") "<")
                         ((string= c "<") ">")
                         ((string= c "'") "'")
                         ((string= c "\"") "\"")
                         (t nil)
                         )
  )

(defun delete-enclosed-text ()
  "Delete texts between any pair of delimiters."
  (interactive)
  (save-excursion
    (let (p1 p2 mychar)
      ; look for one of those characters and store the cursor position
      (skip-chars-backward "^([\'\"><{") (setq p1 (point))
      ; store the char at this point, look for its enclosed char and advance
      ; the cursor newly (this done to avoid the cases when the char and
      ; its enclosed-char are the same like " or ' chars.
      (backward-char 1) (setq mychar (thing-at-point 'char)) (forward-char 1)
      ; look forward for the enclosed char
      (skip-chars-forward (concatenate 'string "^" (get-enc-char mychar))) (setq p2 (point))
      ; only delete the region if we found the enclosed character
      (if (looking-at "[\]\}\"\'\)<>]") (kill-region p1 p2)))))

示例如下:

我速写了一些东西,它与您的要求不完全匹配,但我认为它可以以更舒适的方式满足相同的要求,试试看,让我知道!此交互函数在 select 一个区域 之后被称为 ,没有参数,并要求您提供一个封闭标记:这可以是直接 的任何字符或字符串recognized by replace-regex(直接使用 *.[ 等不会是这种情况,但您仍然可以使用其他字符,例如 {},% 等甚至 HTML-like 标记如 <idx>).

该函数将删除 selected 区域内的所有文本,从标记的第一个出现到最后一个(即使有奇数他们的数量),标记也被删除。

(defun remove-enclosed-in-selection (beginning end)
"select a region, call this function and type any valid regex
 markup. All characters from its first to its last appearance will
 be removed (including the symbol itself. Example: try with § and %:
 aaaa§bbbbcc%c§cc§ddddeeee§ffffgggghhhhiiii§jjjj§kkkkllll§mmmm%nnnn"
(interactive "r")
(let ((x (read-string "type enclosing mark: ")))
  (narrow-to-region beginning end)
  (replace-regexp (concat x ".*" x) "")
  (widen)))

然后您可以像往常一样将它全局绑定到您想要的任何键盘快捷键:

(global-set-key (kbd "C-. <C-return>") 'remove-enclosed-in-selection)

或本地到您可能拥有的任何自定义挂钩:

(defun custom-whatever-hook ()
  (local-set-key (kbd "C-. <C-return>")) 'remove-enclosed-in-selection)
(add-hook 'whatever-hook 'custom-whatever-hook)

所以,总结一下:

  1. select地区
  2. M-x remove-enclosed-in-selection 或您的自定义击键
  3. RET,输入有效标记,按RET
  4. 应删除随附的内容

narrow-widen 方法对我来说似乎又快又脏,但我在短期内找不到其他方法。所以它可能仍然需要一些修复,让我知道它是否按预期工作。另外,我还不是 emacs 黑客……还不是! :P 干杯

这里有一个基于你的代码的解决方案

;; returns the enclosing character for the character "c"
  (defun get-enc-char (c) (cond
                           ((string= c "(") ")")
                           ((string= c "[") "]")
                           ((string= c "{") "}")
                           ((string= c ">") "<")
                           ((string= c "<") ">")
                           ((string= c "'") "'")
                           ((string= c "\"") "\"")
                           (t nil)
                           ))
 (defvar empty-enclose 0)
  (defun delete-enclosed-text ()
    "Delete texts between any pair of delimiters."
    (interactive)
    (setq empty-enclose 0)
    (save-excursion
      (let (p1 p2 orig)
        (setq orig (point))
        (setq p1 (point))
        (setq p2 (point))
        (setq find 0)
        (setq mychar (thing-at-point 'char))
        (if (-contains? '("(" "[" "{" "<" "'" "\"") mychar)
            (progn
              (setq left_encloser (thing-at-point 'char))
              (backward-char -1)
              (if (string-equal (thing-at-point 'char) (get-enc-char left_encloser))
                  (progn
                    (backward-char -1)
                    (setq p2 (point))
                    (setq find 1)
                    (setq empty-enclose 1)))))
        (while (eq find 0)
          (skip-chars-backward "^({[<>\"'")
          (setq p1 (point))
          (backward-char 1)
          (setq left_encloser (thing-at-point 'char))
          (goto-char orig)
          (while (and (not (eobp)) (eq find 0))
            (backward-char -1)
            (skip-chars-forward "^)}]<>\"'")
            (setq right_encloser (thing-at-point 'char))
            (if (string-equal right_encloser (get-enc-char left_encloser))
                (progn
                  (setq p2 (point))
                  (setq find 1))))
          (goto-char p1)
          (backward-char 1))
        (delete-region p1 p2)))
    (if (eq empty-enclose 0)
        (backward-char 1)))