0

Lately, I have seen some cases where I use re-search-forward to find a pattern, and then try to do something with the match, only to find that the match-data is apparently not correct.

For example, in a file I might have this text:

:RESULTS:
async-abcd-1234-output
:END:

I would expect this code to replace async-abcd-1234-output with "string"

(when (re-search-forward "async-abcd-1234-\\(output\\|value\\)" nil t)
  (let ((result-type (match-string 1)))
    (cond ((string= result-type "output")
           (replace-match "string")))))

That works when I run it in a buffer, but when I run it from a callback function I find that (match-string 1) is nil, and even (match-string 0) is "". What could be causing this? I feel like sometimes it works, and then stops working. It is baffling. Any ideas on how to debug this? When I use edebug, I can see the search appears to work, but the match-data isn't correct.

  • That is a typo. It should be joined to spell async. I must separated it to stop tat instance from getting copied. I am on the road now and can't seem to update it on my phone. – John Kitchin Feb 3 '17 at 18:21
  • 1
    Okay, if re-search-forward is returning non-nil, but not setting the match data, my only guess is perhaps inhibit-changing-match-data somehow gets bound in that case? – npostavs Feb 3 '17 at 18:29
  • 1
    You do not show anything about the calling context, so it is difficult to guess why (match-string 1) returns nil. Show the code for how you are using the code you showed. It sounds like you are searching in the wrong buffer, or with point at the wrong buffer position. You say that your code "works in a buffer, but not..." what do you mean by it not being in a buffer? Unless you provide a string argument, re-search-forward always searches the text in a buffer. The question now seems unclear - underspecified. Originally it seemed that the "typo" you refer to was your problem... – Drew Feb 3 '17 at 21:37
  • Have you tried using debug-on-entry or inserting calls to message to determine which buffer you are searching and where point is? If not, that would be a good first step. – Drew Feb 3 '17 at 21:38
  • Inspecting the match data with edebug might be misleading as that could change while you're looking at it. Better insert a few good old 'message' calls to show context such as current buffer, text around point, match data etc. Both just after searching and just before replacing. – YoungFrog Feb 3 '17 at 22:15
1

I think you want to give the function a single string REGEXP argument, not two separate strings:

(re-search-forward "async-abcd-1234-\\(output\\|value\\)" nil t)

And you want to replace only the first match group, not the entire match, so you want this:

(replace-match "string" nil nil nil 1)

In other words:

(defun foo ()
  (interactive)
  (when (re-search-forward "async-abcd-1234-\\(output\\|value\\)" nil t)
    (let ((result-type (match-string 1)))
      (cond ((string= result-type "output")
             (replace-match "string" nil nil nil 1))))))
  • I did want to replace the whole match. The issue is the example I gave works in a buffer but not when I call it from code. When called in a function it seems the match data isn't set correctly even though if I run with edebug I can see the search found the regexp in the buffer. – John Kitchin Feb 3 '17 at 11:53
  • If you want to replace the whole match then just remove the last 4 args from the call to replace-match. – Drew Feb 3 '17 at 21:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.