【发布时间】:2012-06-23 05:43:12
【问题描述】:
是否可以在 emacs 的矩形区域内执行replace-string 操作?如果有,怎么做?
【问题讨论】:
是否可以在 emacs 的矩形区域内执行replace-string 操作?如果有,怎么做?
【问题讨论】:
在最近的 Emacs(例如 Emacs 25)中,您可以使用 M-% (query-replace) 或 C-M-% (query-replace-regexp) 开箱即用地执行此操作。
使用M-x rectangle-mark-mode 创建矩形区域。如有必要,使用C-x C-x 将点放在标记之前。然后只需查询替换。
然而,他们并没有在 Emacs 25 中为 replace-string 进行相同的更改。如果你愿意,你可以这样做,只需添加参数region-noncontiguous-p,就像在query-replace 中一样。代码很简单:
(defun replace-string (from-string to-string &optional delimited start end backward
region-noncontiguous-p)
"..."
(declare (interactive-only
"use `search-forward' and `replace-match' instead."))
(interactive
(let ((common
(query-replace-read-args
(concat "Replace"
(if current-prefix-arg
(if (eq current-prefix-arg '-) " backward" " word")
"")
" string"
(if (use-region-p) " in region" ""))
nil)))
(list (nth 0 common) (nth 1 common) (nth 2 common)
(if (use-region-p) (region-beginning))
(if (use-region-p) (region-end))
(nth 3 common)
(if (use-region-p) (region-noncontiguous-p)))))
(perform-replace
from-string to-string nil nil delimited nil nil start end backward region-noncontiguous-p))
或者,您可以只下载库replace+.el 并从那里使用replace-string 的版本。它做你想做的事。
FWIW,我刚刚提交了 Emacs bug#27897 以将此功能添加到 replace-string 和同一库中的其他几个命令 replace.el。
【讨论】:
query-replace 版本):github.com/syohex/emacs-anzu/issues/69
对于邪恶的用户,您可以使用我的包evil-visual-replace 来获取邪恶视觉块内的query-replace 和replace-regexp。
【讨论】:
如果您处于 CUA 模式,您可以使用绑定到 'M-r' 的 cua-replace-in-rectangle。
【讨论】:
如果启用 CUA 选择模式:
M-x cua-selection-mode RET
或永久保存在您的初始化文件中:
(cua-selection-mode 1)
然后您可以使用它的高级矩形编辑工具。
(或者如果您是cua-mode 用户,则不需要这样做。)
有关文档,请在 Mx find-library RET cua-base RET
如果您出于某种原因不想使用 cua 矩形功能(也许如果您真的特别需要 replace-string),那么使用 apply-on-rectangle 的自定义函数将非常简单。
编辑:实际上,比我预期的要复杂一些,但大部分代码是交互式规范和对“分隔”前缀参数行为的支持(均基于replace-string) .
编辑 2:我认为这值得以更全面的方式进行:
以下提供CxrM-%和CxrCM-%,它(希望)按照你的预期行事。
(require 'rect)
(defun my-search-replace-in-rectangle
(start end search-pattern replacement search-function literal)
"Replace all instances of SEARCH-PATTERN (as found by SEARCH-FUNCTION)
with REPLACEMENT, in each line of the rectangle established by the START
and END buffer positions.
SEARCH-FUNCTION should take the same BOUND and NOERROR arguments as
`search-forward' and `re-search-forward'.
The LITERAL argument is passed to `replace-match' during replacement.
If `case-replace' is nil, do not alter case of replacement text."
(apply-on-rectangle
(lambda (start-col end-col search-function search-pattern replacement)
(move-to-column start-col)
(let ((bound (min (+ (point) (- end-col start-col))
(line-end-position)))
(fixedcase (not case-replace)))
(while (funcall search-function search-pattern bound t)
(replace-match replacement fixedcase literal))))
start end search-function search-pattern replacement))
(defun my-replace-regexp-rectangle-read-args (regexp-flag)
"Interactively read arguments for `my-replace-regexp-rectangle'
or `my-replace-string-rectangle' (depending upon REGEXP-FLAG)."
(let ((args (query-replace-read-args
(concat "Replace"
(if current-prefix-arg " word" "")
(if regexp-flag " regexp" " string"))
regexp-flag)))
(list (region-beginning) (region-end)
(nth 0 args) (nth 1 args) (nth 2 args))))
(defun my-replace-regexp-rectangle
(start end regexp to-string &optional delimited)
"Perform a regexp search and replace on each line of a rectangle
established by START and END (interactively, the marked region),
similar to `replace-regexp'.
Optional arg DELIMITED (prefix arg if interactive), if non-nil, means
replace only matches surrounded by word boundaries.
If `case-replace' is nil, do not alter case of replacement text."
(interactive (my-replace-regexp-rectangle-read-args t))
(when delimited
(setq regexp (concat "\\b" regexp "\\b")))
(my-search-replace-in-rectangle
start end regexp to-string 're-search-forward nil))
(defun my-replace-string-rectangle
(start end from-string to-string &optional delimited)
"Perform a string search and replace on each line of a rectangle
established by START and END (interactively, the marked region),
similar to `replace-string'.
Optional arg DELIMITED (prefix arg if interactive), if non-nil, means
replace only matches surrounded by word boundaries.
If `case-replace' is nil, do not alter case of replacement text."
(interactive (my-replace-regexp-rectangle-read-args nil))
(let ((search-function 'search-forward))
(when delimited
(setq search-function 're-search-forward
from-string (concat "\\b" (regexp-quote from-string) "\\b")))
(my-search-replace-in-rectangle
start end from-string to-string search-function t)))
(global-set-key (kbd "C-x r M-%") 'my-replace-string-rectangle)
(global-set-key (kbd "C-x r C-M-%") 'my-replace-regexp-rectangle)
【讨论】:
C-RET 标记一个角落,而不是在终端模式下。
DPP 之外是否还有其他内容。我使用了一些复杂的正则表达式——如果列真的很大——我得到正则表达式堆栈溢出。