This is related to Emacs: regular expression replacing to change case
My additional problem is that I need to script the search-replace but the "\,()"
solution works (for me) only when used interactively (emacs 24.2.1)
. Inside a script it gives the error: "Invalid use of \'
in replacement text".
I usually write a "perform-replace" to some file to be loaded when needed. Something like:
(perform-replace "<\\([^>]+\\)>" "<\\,(downcase \1)>"
t t nil 1 nil (point-min) (point-max))
It should be possible to call a function to generate the replacement (pg 741 of the emacs lisp manual)
, but I've tried many variations of the following with no luck:
(defun myfun ()
(downcase (match-string 0)))
(perform-replace "..." (myfun . ()) t t nil)
Can anyone help?
Constructs like \,()
are only allowed in interactive calls to query-replace
, which is why Emacs complains in your case.
The documentation of perform-replace
mentions that you should not use it in elisp code and proposes a better alternative, upon which we can build the following code:
(while (re-search-forward "<\\([^>]+\\)>" nil t)
(replace-match (downcase (match-string 0)) t nil))
If you still want to interactively query the user about the replacements, using perform-replace
like you did is probably the right thing to do. There were a few different problems in your code:
As stated in the elisp manual the replacement function must take two arguments (the data you provide in the cons cell and the number of replacements already made).
As stated in the documentation of query-replace-regexp
(or the elisp manual), you need to ensure that case-fold-search
or case-replace
is set to nil so that the case pattern is not transferred to the replacement.
You need to quote the cons cell (myfun . nil)
, otherwise it will be interpreted as a function call and evaluated too early.
Here is a working version:
(let ((case-fold-search nil))
(perform-replace "<\\([^>]+\\)>"
`(,(lambda (data count)
(downcase (match-string 0))))
t t nil))
C-h f perform-replace
says:
Don't use this in your own program unless you want to query and set the mark
just as `query-replace' does. Instead, write a simple loop like this:
(while (re-search-forward "foo[ \t]+bar" nil t)
(replace-match "foobar"))
Now the "<\\,(downcase \1)>"
needs to be replaced by an Elisp expression that builds the proper string, such as (format "<%s>" (downcase (match-string 1)))
.
If you do need the query and stuff, then you might like to try: C-M-% f\(o\)o RET bar \,(downcase \1) baz RET
and then C-x RET RET
to see what arguments were constructed during the interactive call.
You'll see discover (even better if you click on replace.el
in C-h f perform-replace
to see the source code of the function), that the replacements
argument can take the form (FUNCTION . ARGUMENT). More specifically, the code includes a comment giving some details:
;; 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With