2

Since version 22 of Emacs, we can use \,(function) for manipualting (parts of) the regex-search result before replacing it. But – this is mentioned often, but nonetheless still the truth – we can use this construct only in the standard interactive way. (Interactive like: By pressing C-M-% or calling query-replace-regexp with M-x.)

As an example:

If we have

  • [Foo Bar 1900]

and want to get

  • [Foo Bar \function{foo1900}{1900}]

we can use:

M-x query-replace-regexp <return>
  \[\([A-Za-z-]+\)\([^0-9]*\) \([0-9]\{4\}\)\]    
  [\1\2 \\function{\,(downcase \1)\3}{\3}] 

to get it done. So this can be done pretty easy.

In my own defun, I can use query only by replacing without freely modifying the match, or modify the prepared replaced string without any querying. The only way I see, is to serialize it in such a way:

(defun form-to-function () 
  (interactive)
  (goto-char (point-min))
  (while (query-replace-regexp 
    "\\[\\([A-Za-z-]+\\)\\([^0-9]*\\) \\([0-9]\\{4\\}\\)\\]" 
    "[\\1\\2 \\\\function{\\1\\3}{\\3}]" ))
  (goto-char (point-min))
  (while (search-forward-regexp "\\([a-z0-9]\\)" nil t) 
    (replace-match (downcase (match-string 1)) t nil)
 )
)

For me the query is important, because I can't be sure, what the buffer offers me (= I can't be sure, the author used this kind of string always in the same manner).

I want to use an elisp function, because it is not the only recurring replacement (and also not only one buffer (I know about dired-do-query-replace-regexp but I prefer working buffer-by-buffer with replace-defuns)).

At first I thought I only miss something like a query-replace-match to use instead of replace-match. But I fear, I am also missing the easy and flexible way of rearrange the string the the query-replace-regexp.

So I think, I need a \, for use in an defun. And I really wonder, if I am the only one, who is missing this feature.

3
  • 3
    As you say query-replace-regexp is for interactive use only. In lisp code one uses read-key or y-or-n-p to query the user whether to replace the text or not. AFAIK, the only reasonable way to modify the behaviour of query-replace-regexp temporarily is to let replace-re-search-function to a function which replaces the action of re-search-forward in query-replace-regexp. Note, you should replace (goto-char 1) with (goto-char (point-min)) in your code. That leaves the user more freedom to restrict the area to be processed. Commented Aug 11, 2015 at 5:24
  • @Tobias: As Stefan mentioned, I can use query-replace-regexp in a defun, also it is not suggested. (Perhaps because a query is not thought as a wish?) But anyway, I fear I wasn't precise enough. I don't want to modify the behaviour of query-replace-regexp, I want to use the functionality I have with [C-M-%] combined with \, in a defun. In other words: I'm searching for an easy to use search and manipulate replace function for my defun. Thank you very much, also for pointing me to use (point-min) instead of just 1. I refined my question. Commented Aug 13, 2015 at 2:07
  • I think read-key and y-or-no-p just asks for approval but doesn't present the highlighted match and moreover doesn't show the resulting replacement in the minibuffer, which is very convenient. Commented Aug 13, 2015 at 3:10

2 Answers 2

2

If you want your rsearch&replace to prompt the user, that means you want it to be interactive, so it's perfectly OK to call query-replace-regexp (even if the byte-compiler will tell you that this is meant for interactive use only). If the warning bothers you, you can either wrap the call in with-no-warnings or call perform-replace instead.

The docstring of perform-replace sadly doesn't (or rather "didn't" until today) say what is the format of the replacements argument, but you can see it in the function's code:

;; REPLACEMENTS is either a string, a list of strings, or a cons cell
;; containing a function and its first argument.  The function is
;; called to generate each replacement like this:
;;   (funcall (car replacements) (cdr replacements) replace-count)
;; It must return a string.
Sign up to request clarification or add additional context in comments.

5 Comments

I did not get the point, why it seems to be unsuggested using the query-replace-regexp in a defun, but I've never seen a warning, because I've never thought to byte-compile the .el file, I think because of the heavy use of query it'll me, who slows down the process.
And: I have to admit, I don't get to use perform-replace. Does it replace the query-replace-regexp or just the replace-match in a loop with re-search-forward? What I didn't know until now, the replacement of an query-replace-regexp doesn't have to be a string, one can also use a list.
C-h f perform-replace should explain that: it does search and replace in a loop.
At the first try, I did not understand the help of perform-replace, but anyway, my problem was the forming of the replacement element of the defun. As it is the same as for query-replace-regexp, your answer didn't achieve what I thought I was asking for. But it helped me a lot indeed, that's why I'll upvote it anywaym, as soon as I am allowed to.
BTW, the reason why we discourage the use of query-replace-regexp in Elisp is because it is too common for beginners to use this function (presumably because it's the one they know from interactive use) when they really don't want all the interactive part of it (they just want to unconditionally search&replace all the matches), in which case they should use the simple while loop shown in the docstring instead. Clearly, you're in a different situation, because you do want to use the interactive features.
1

The query-replace-function can handle replacement not only as a string, but as a list including the manipulating elements. The use of concat archives building an string from various elements.

So one who wants to manipulate the search match by a function before inserting the replacement can use query-replace-regexp also in a defun.

(defun form-to-function () 
  (interactive)
  (goto-char (point-min))
  (query-replace-regexp 
   "\\[\\([A-Za-z-]+\\)\\([^0-9]*\\) \\([0-9]\\{4\\}\\)\\]"
   (quote (replace-eval-replacement concat "[\\1\\2 \\\\function{" 
    (replace-quote (downcase (match-string 1))) "\\3}{\\3}]")) nil ))
  • match-string 1 returns the first expression of our regexp-search.

  • `replace-quote' helps us doublequoting the following expression.

  • concat forms a string from the following elements.

and

  • replace-eval-replacement is not documented.

Why it is in use here nevertheless, is because of emacs seems to use it internally, while performing the first »interactive« query-replace-regexp call. At least is it given by asking emacs with repeat-complex-command.

I came across repeat-complex-command (bound to [C-x M-:].) while searching for an answer in the source code of query-replace-regexp.

So an easy to create defun could be archieved by performing the standard search and replace way as told in the question and after first sucess pressing [C-x M-:] results in an already Lisp formed command, which can be copied and pasted in a defun.

Edit (perform-replace)

As Stefan mentioned, one can use perform-replace to avoid using query-replace-regexp.

Such a function could be:

(defun form-to-function () 
  (interactive)
  (goto-char (point-min))
  (while (perform-replace
      "\\[\\([A-Za-z-]+\\)\\([^0-9]*\\) \\([0-9]\\{4\\}\\)\\]"
      (quote (replace-eval-replacement concat "[\\1\\2 \\\\function{"
      (replace-quote (downcase (match-string 1))) "\\3}{\\3}]"))
       t t nil)))

The first boolean (t) is a query flag, the second is the regexp switch. So it works also perfectly, but it didn't help finding the replacement expression as easy as in using \,.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.