Emacs 新增 replace-regexp-in-region 的疑问

Emacs 28.1 发布了, tag 已经打了。继续讨论:

我正在通过看 28.1 的 NEWS 文件学习新变化,更新下 elisp-demos 中的例子。遇到一个新函数 replace-regexp-in-region,我试了下,对它的行为有疑问:

(replace-regexp-in-string "[0-9]" "XX" "#1 #2 #3")
;; => "#XX #XX #XX"

(with-temp-buffer
  (insert "#1 #2 #3")
  (replace-regexp-in-region "[0-9]" "XX" (point-min))
  (buffer-string))
;; => "#XX #XX #3"

我看过了 replace-regexp-in-region 的实现,知道它受替换 REPLACEMENT 的长度的影响,长度比原来的长,甚至搜索范围溢出而报错,现在的这种还有多大用吗?就是故意如此设计的吗?

(with-temp-buffer
  (insert "#1 #2 #3")
  (replace-regexp-in-region "[0-9]" "XXX" (point-min))
  (buffer-string))
;; -> (error "Invalid search bound (wrong side of point)")

replace-regexp-in-region 用起来挺奇怪的:

(with-temp-buffer
  (insert "#1 #2 #3 a")
  (replace-regexp-in-region "[0-9]" "XX" (point-min))
  (buffer-string))

;; → replace-regexp-in-region: Invalid search bound (wrong side of point)

还是习惯这样:

(with-temp-buffer
  (insert "#1 #2 #3")
  (goto-char (point-min))
  (while (re-search-forward "[0-9]" nil t)
    (replace-match "XX" nil nil ))
  (buffer-string))

;; → "#XX #XX #XX"

如果改为从尾部开始替换就不会出错了:

-     (goto-char start)
-     (while (re-search-forward regexp end t)
+     (goto-char end)
+     (while (re-search-backward regexp start t)
(with-temp-buffer
  (insert "#1 #2 #3 a")
  (replace-regexp-in-region "[0-9]" "XX" (point-min))
  (buffer-string))
;; => "#XX #XX #XX a"