《elisp 每日一练》——文本插入、删除、替换

《elisp 每日一练》——文本插入、删除、替换

Masimaro
2026-08-08 / 0 评论 / 1 阅读 / 正在检测是否收录...

对于文本操作的增删改查,我在前一天已经了解了关于查相关的操作。今天我们来了解增删改。

背景知识

文本增删比较简单,我们只需要确定光标位置,然后调用相关函数即可。

文本的增加或者说插入我们通过函数 insert 来执行。它的函数原型如下:

(insert &rest ARGS)

它用来在光标所在位置之后插入对应文本,从函数定义上,我们知道这个函数后面可以跟一个或者多个参数。也是就是说我们实际上可以一次插入多个字符串。

我们需要注意的是光标和mark的变化,插入结束之后,光标位于插入文本的末尾,而mark由Emacs维护,它会随着文本的变化而变化。

删除我们使用函数 delete-region 它的函数原型如下:

(delete-region START END)

它用来删除从 STARTEND 区域内的文本。而光标位置会在原来的基础上减去被删除的字符数。而 mark 因为是由Emacs自己维护的,所以如果 mark 位于 START 之前,那么它的位置不会发生变化,在END 之后,它的位置会相应的减去 END - START 的值。如果在 STARTEND之间,那么它会被放到 START的位置。

增加和删除比较简单,光标和 mark 位置的变化也跟我们平时使用编辑器的习惯一致。这个部分稍微复杂一些的操作是修改。

一般来讲,修改之前会进行查找并且对匹配上的部分进行修改,所以它天然的就离不开正则表达式。

Emacs 中,通过函数 replace-match 来进行。它的函数原型如下:

(replace-match NEWTEXT &optional FIXEDCASE LITERAL STRING SUBEXP)

它的核心参数为:

  • NEWTEXT : 替换后的新文本
  • FIXEDCASE : 如果为 nil Emacs在替换时采用智能大小写机制。(例如原词是大写,替换词也会自动转大写),如果为 t 会强制按照 NEWTEXT 的原始值
  • LITERAL : 若为 tNEXTTEXT 被视为纯文本,否则允许在 NEWTEXT 中使用 \1\2 来引用正则捕获组
  • SUBEXP : 指定只替换第 N 个捕获组,而不是整个匹配项

另外在上一篇我们知道,Emacs中匹配结果非常脆弱,它永远只保留最近一次匹配的结果。我们应该即时通过 match-string 获取并保存结果。但是如果我们确实需要在后续再重新获取怎么办?Emacs提供了一个保护现场的函数 save-match-data

到这里我们已经知道了三个保存现场的函数 save-excursionsave-restrictionsave-match-data

练习

到这里我们已经可以尝试对文本进行操作了。我们来尝试一下将所有 foo_ 为前缀的函数替换为 my/foo_ 。因为Emacs 中的函数定义以 (defun 开头,所以我们实际上匹配的就是 (defun foo_

下面是我的实现

(defun my/profix-internal-functions()
  (interactive)
  (let ((count 0))
    (save-excursion
      (save-restriction
    (widen)
    (goto-char (point-min))
    (while (re-search-forward "(defun \\(foo_[a-zA-Z0-9-]+\\)" nil t)
      (setq count (1+ count))
      ;; 用 \1 引用捕获匹配到的函数名称, 参数t表示维持原来的大小写 参数3为nil表示替换的字符串中允许使用 \1 这种来匹配原来的捕获
      (replace-match "(defun my/\\1" t nil))))
    (message "重构完成,共修改 %d 个函数名" count)))

到此我们已经掌握了移动光标和操作文本的大部分操作了。基于此我们就可以完成日常操作文本的任务了。后面我们将对之前的内容进行一个总结,并完成一个基础的小功能。敬请期待!

0

评论 (0)

取消