This page shows you how to use a elisp function in your regex replacement. This lets you do transformation of the matched text. For example, replacing “_” to space, or insert timestamp, current file name, in your replacement text.
Suppose you have thousands of links to Wikipedia in the following form, spread over 5 thousand HTML pages:
① <a href="…/Emacs_Lisp">Emacs Lisp</a>
② <a href="…/Emacs_Lisp">Emacs_Lisp</a>
③ <a href="…/Emacs_Lisp">http://en.wikipedia.org/wiki/Emacs_Lisp</a>
You want format 2 and 3 to be replaced with format 1, but on case-by-case basis. (some of them you want the URL in the link text, depending on the article.)
For simplicity, let's say i just want to replace format 2 to format 1 on a case-by-case basis.
In emacs 22 (released in ), there's a new feature that allows you use a function as your replacement string.
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.
Let's say our function will be named ff. ff will take 1 input that's the matched text, then replace
_ by space, then return the new text.
Here's our function template:
(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)) )
(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.
(To make emacs aware of
ff, select the whole definition, then call
So, with this function written, we can call
dired-do-query-replace-regexp, then give this pattern:
And the replacement expression would be:
and we are all done.
You can use this technique to do find replace on all files in a dir, including subdirectories. Call
find-dired. For detail, see Emacs: Interactively Find/Replace String Patterns on Multiple Files.
To save and close all changed files, call
ibuffer and type 【* u S D】. For detail, see Emacs: List Buffers.
Whenever you need to replace text patterns by a function, you can use this template:
(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 ) )
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:
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>") ))
Here are more examples of using a function as replacement string.