5

我经常发现自己需要连续执行几个查询和替换操作,因为例如我想将一行中所有出现的 23 更改为 24,然后将下一行中的 24 更改为 25,依此类推(通常是因为我写一行中的一个表达式,我在后续行中多次拉取并需要稍微修改)...

在这样的情况下,具有 Cx q 或常规执行多个查询替换的宏似乎不够强大..是否有更通用/灵活的方法来处理像这样的变量替换或变量宏变体,我可以研究一下?我相信我曾经在网上遇到过一个示例,其中将 lisp 表达式引入某些命令以使其更强大,但我不记得这个或我在哪里读到它。

4

4 回答 4

6

我不确定这是否完全回答了您的问题,但我发现寄存器是构建强大宏的有用工具。最重要的功能是:

  • C-x r n number-to-register将该点的数字复制到寄存器中
  • C-x r + increment-register递增存储在寄存器中的值
  • C-x r i insert-register将寄存器的值插入缓冲区

使用这些函数,您可以解决将每行上的递增数字替换为:

  • 将第一个数字播种到寄存器中number-to-register
  • 开始宏定义
  • 选择一行
  • replace-string, insert-register, increment-register,insert-register
  • 移动到下一行的开头
  • 结束宏定义

在 emacs 手册中有更多关于寄存器的信息:https ://www.gnu.org/software/emacs/manual/html_node/emacs/Registers.html

于 2012-04-30T19:22:07.083 回答
3

除了巧妙地使用现有命令(例如 ataylor 所示的命令)外,还可以使用键盘宏来执行几乎任意复杂的动态行为。

特别要注意的是,C-uM-:会将您输入的任何 elisp 表单的结果插入到当前缓冲区中——当然,该表单可以作为宏的一部分构建——因此,即使不存在用于特定操作的命令,您也可以不太可能阻止使用宏来实现您的目标。

(当然,如果 elisp 不是答案,C-uM-!C-uM-|可以让您轻松访问合并 shell 命令输出。)

当然,在某些情况下,可以使用更有针对性的解决方案,而宏比它的价值更麻烦(评论中链接的“使用 elisp 评估搜索和替换”技术也非常强大,而且通常是理想的解决方案);然而,键盘宏也提供了惊人的功能,而且只需极少的努力,并且可以轻松完成一些您可能难以实现的事情。

我最喜欢的示例之一是在一个缓冲区中使用“旧 -> 新”映射数据(几乎可以采用任何可以想象的格式),并使用它对另一个缓冲区中的这些值执行搜索和替换。只需简单的移动和编辑击键,您就可以临时做这种事情的速度是惊人的。

如果第一次不正确,宏编辑器还可以轻松调整宏,而无需重新记录所有步骤。

有一次我读到了一些有用的建议,它只是想在遇到不平凡的事情时始终考虑是否可以使用键盘宏来完成任务。您使用它们的次数越多,您就越会意识到可以使用它们的不同方式,很快您的工具箱中就会出现一个新的不可或缺的工具。

于 2012-05-01T11:03:57.420 回答
2

您询问的具体情况听起来像是使用的理想场所query-replace-regexp

M-x query-replace-regexp
Regexp: \([0-9]+\)
Replace with: \,(+ 1 (string-to-number \1))

该用法将找到所有一组一个或多个数字(Emacs 正则表达式不支持\d)并用它们的增量替换它们,每次都会提示。

关键要点是:

  • 捕获的组是您可以在替换操作中调用的字符串
  • 您可以将任意代码拼接到替换操作中\,
  • 您可以在以这种方式拼接的任何代码中使用捕获的组作为参数
于 2012-05-01T13:32:46.323 回答
1

这是您陈述的问题的另一种可能的解决方案,使用 elisp 替换和键盘宏计数器,您可以使用数字前缀参数作为种子。

(我不会说这更好,但它展示了另一个可用的选项。)

所以假设 23 是起始数字,您可以定义以下宏,从:

C-2C-3F3

C-SPC       ;; set-mark-command
C-e         ;; move-end-of-line
<<replace-regexp>>  ;; replace-regexp
<f3>        ;; kmacro-start-macro-or-insert-counter
C--         ;; negative-argument
M-@         ;; mark-word
M-w         ;; kill-ring-save
RET         ;; indent-new-comment-line
\           ;; self-insert-command
,(1+        ;; self-insert-command * 4
SPC         ;; self-insert-command
C-y         ;; yank
)           ;; self-insert-command
RET         ;; indent-new-comment-line

F4停止录制。

(注:此宏假定区域中的每一行都包含序列中的一个值。)

然后突出显示剩余的行并使用C-xC-kr更新该区域中的所有行。

您可以将宏计数器重新设置为任何所需的值,C-xC-kC-c以便在另一个区域重新播放宏。

并且根据您的数据的实际外观,您可以通过完全消除替换正则表达式来大大简化它,而只是移动到您知道数字所在的位置,删除现有数字,并在其位置插入计数器值。

于 2012-05-01T14:06:06.467 回答