[求助] 关于 replace-match 使用的疑问

有如下的代码:

(while (re-search-forward gkroam-link-regexp nil t)
  (replace-match
   (gkroam--format-backlink
    (gkroam--get-page (match-string-no-properties 2))
    (match-string-no-properties 2))))

目的是搜索符合正则的字符串后,使用 replace-match 替换为 一个经过 gkroam--format-backlink 函数处理过的字符串。 gkroam--format-backlink 函数中使用了 匹配的字符串的分组作为参数。

运行结果报错:(args-out-of-range 0 1),这里 replace-match 的用法有问题吗?烦请大佬赐教。

backtrace是什么样的?

这个正则表达式是什么?

这些gkroam开头的函数是什么?

谢谢,刚刚解决了。原因是 gkroam--get-page 函数中也有搜索的操作,导致这里的 match-data 被污染了。现在,我将所有的 title 和 filename 缓存在了hashtable 里,不使用实时搜索就没问题了。

这个报错信息缺吧,我这里 Emacs 27.1 会给出 Buffer 信息

(args-out-of-range #<buffer foo> 5 6)

字符串越界也会给出字符串。

buffer-substring/substring。

就是这样的,我是从 backtrace 复制的。我是直接在 buffer 里面 用 eval-expression 测试的代码,可能是这个原因吧。

借楼提问,我用replace-match时同样报错 Args out of range: 0, 7,代码如下:

(while (re-search-forward org-media-note--timestamp-pattern
                                nil t)
        (let* ((hms (buffer-substring (match-beginning 1)
                                      (match-end 1)))
               (adjusted-hms (org-media-note--seconds-to-hms (+ (org-timer-hms-to-secs hms)
                                                                offset))))
          (replace-match adjusted-hms 'fixedcase)))

其中, org-media-note--timestamp-pattern"\\([0-9]+:[0-9]+:[0-9]+\\)[ \t]?" 用于匹配hms, adjusted-hms 是一个字符串,在运行到 replace-match 的时候,adjusted-hms 已正确计算。

现在发现似乎是由于 (org-timer-hms-to-secs hms) 引起的,是因为该函数内部使用了 string-match?我现在把replace-match 改成了 delete-region + insert。不知道有没有更好的方法?

简单的例子:

(while (re-search-forward "\\([0-9]+:[0-9]+:[0-9]+\\)[ \t]?" nil t)
  (replace-match "xxx" nil nil ))

01:44:20

没有问题,但:

(while (re-search-forward "\\([0-9]+:[0-9]+:[0-9]+\\)[ \t]?" nil t)
  (org-timer-hms-to-secs "01:44:20")
  (replace-match "xxx" nil nil ))

01:44:20

Debugger entered--Lisp error: (args-out-of-range 0 8)

看来是org-timer-hms-to-secs中的 match-string 污染问题。类似于楼主原因:

原因是 gkroam--get-page 函数中也有搜索的操作,导致这里的 match-data 被污染了。

想到一个办法是将搜索,保存分成两个函数。

第一次函数负责在搜索的过程中,写成一个列表。第二个用来替换。

有个save-match-data,把你不希望污染match data的部分用它包起来就好了。我翻了一下自己的配置,发现它通常的用法是放在一个函数的最外层,这样这个函数在对当前buffer进行搜索时不会污染用户的match data。

我看到的 save-match-data都是和 string-match 配合使用,并保存最后一个值。它也是可以和 re-search-forward 配合,保存所有匹配值?

可以的,一样的。

看文档就知道了,两种search用的同一个系统保存match data。话说 save-match-data有点misleading,他其实应该叫做“丢弃下面这段代码产生的match data”