ELisp: Call Function in Replacement String

By Xah Lee. Date: . Last updated: .

This page shows you how to use a elisp function in your regex replacement.

For example, replace “_” to space in matched pattern.

In the replace string prompt, give \,(function_name), where function_name is your elisp function. The function's return value will be used as the replacement string.

Following are details.

Problem

Suppose you have thousands of links like this:

<a href="…/this_and_that">this_and_that</a>

you want to change the link text so that _ is replaced by space, like this:

<a href="…/this_and_that">this and that</a>

First, you need to use regex find replace to match the links. Then, you need a function to transform the matched pattern.

Call Function in Replacement String

You can use a function as your replacement string. (new in emacs 22, released in )

In the replace string prompt, give \,(function_name), where function_name is your elisp function.

The function needs no argument. Its return value is used as the replacement string.

The task here is to write the replacement function.

Solution

Here's our function sketch:

(defun ff ()
  "temp function. Returns a string based on current regex match."
; 1. get the matched text
; 2. transform the matched text
; 3. returns the transformed text
)

How do we actually get the matched text? Here's the solution:

(defun ff ()
  "return matched text with underscore replaced by space."
  (replace-regexp-in-string "_" " " (match-string 1))
)

To make emacs aware of ff, Evaluate Emacs Lisp Code.

The (match-string 1) gives you the first captured string. (“1” is for 1st captured pattern, “2” for 2nd captured pattern. “0” is the entire match.).

The replace-regexp-in-string is used to transform the text.

So, with this function written, we can call query-replace-regexp, then give this pattern:

>\([_A-Za-z0-9]+\)</a>

And the replacement expression would be:

\,(ff)

and we are all done.

To save and close all changed files, Alt+x ibuffer and type * u S D. For detail, see Emacs: List Buffers.

You can use this technique to do find replace on all files in a dir.

[see Emacs: Regular Expression]

[see Emacs: Interactive Find Replace Text in Directory]

Replacement Function Template

Here's a example where i need to find all Wikipedia links and change the link text to use space instead of _.

(defun wikipedia-link-replacement ()
  "Returns a canonical form of Wikipedia link from a regex match.

The regex to be used for this function is:

 <a href=\"http://\\(..\\)\\.wikipedia.org/wiki/\\([^\"]+\\)\">\\(\\([-.A-Za-z0-9]+_\\)+[-.A-Za-z0-9]+ ?\\)</a>

To use this function, call `query-replace-regexp', then in the replacement prompt give:
 \\,(wikipedia-link-replacement)
"
  (let (langCode articlePath linkText linkText2 returnText)
    (setq langCode (match-string 1))
    (setq articlePath (match-string 2))
    (setq linkText (match-string 3))
    (setq linkText2 (replace-regexp-in-string "_" " " articlePath))
    (setq returnText
          (concat "<a href=\"http://"
                  langCode ".wikipedia.org/wiki/"
                  articlePath "\">" linkText2 "</a>" ))
    returnText ) )

Example: Replace Emacs Manual Links

Here's another example of batch find replace using a function for replacement.

I need to find all text of the form:

(info "(emacs) Option Index")

and change it into this form:

<a href="../emacs_manual/Option-Index.html">(info "(emacs) Option Index")</a>

Here's the regex i use:

(info "(emacs) \([^"]+?\)")

Here's the replacement code: \,(ff).

Here's the elisp code:

(defun ff ()
  "temp"
  (interactive)
  (let (matchedText url replaceText anchorText)
    (setq matchedText (match-string 1 ) )
    (setq replaceText (replace-regexp-in-string " " "-" matchedText))
    (setq url (concat "../emacs_manual/" replaceText ".html" ) )
    (setq anchorText
          (concat
           "(info \"(emacs) "
           matchedText
           "\")"
           )
          )
    (concat "<a href=\"" url "\">" anchorText "</a>")
    ))

Function as Replacement String