1

Somethimes I need a RegExp which uses a complex pattern multiple times. If I copy the same pattern there it works, but this is error prone as I then need to change each occurence of the pattern individualy if I want to make changes in the future.

Is there a way to either name a pattern, or even better, store it somewhere so that I can reuse it over multiple functions?

Consider the following code:

(defun complex-stuff ()
  ""
  (interactive)
  (beginning-of-buffer)
  (save-excursion 
    (query-replace-regexp  
      "a \\(<complex-patten>\\) b \\(<complex-pattern>\\)"
      "x \\1 y \\2")))

Here, <complex-pattern> is some valid expression that I wish to reuse.

  • @sds: It's fine this way for me. I can see in separate lines which expression will be replaced by which other What would you do differently? – Shylock May 17 '17 at 14:40
  • Hit TAB on each line and Emacs will indent it. Avoid hanging parens. Look at the conventions. I am sure it looks fine to YOU, but you write code for others (and yourself down the road) to read, not just for the computer to execute. – sds May 17 '17 at 14:43
3

A regular expression is just a string, so you can store it as such in a variable:

(defvar my-complex-patters "....")
(re-search-forward (concat "a \\(" my-complex-patters "\\)"))

or even

(re-search-forward (format "a \\(%s\\)" my-complex-patters))

NB: Please note that query-replace-regexp is a fairly complicated command which depends on many user options. Its use in code is fragile and thus is discouraged.

You should do something like this instead:

(while (re-search-forward ... nil t)
  (replace-match ...))
2

Regular expressions are just strings in Elisp, so you can assign them as the value of a variable like any other Elisp value. For example:

(defvar my-complex-pattern "\\(<complex-pattern>\\)"
  "Regular expression matching desired filename.")

(defun complex-stuff ()
  "Do complex stuff."
  (interactive)
  (goto-char (point-min))
  (save-excursion
    (query-replace-regexp
     (apply #'format "a %s b %s" (make-list 2 my-complex-pattern))
     "x \\1 y \\2")))

You can also locally assign the regular expression to a let-bound variable like so:

(defun complex-stuff ()
  "Do complex stuff."
  (interactive)
  (goto-char (point-min))
  (save-excursion
    (query-replace-regexp
     (let ((patt "\\(<complex-pattern>\\)"))
       (apply #'format "a %s b %s" (make-list 2 patt)))
     "x \\1 y \\2")))

An alternative to using concat and format to dynamically construct regular expressions is rx-to-string (see documentation for macro rx):

(defun complex-stuff ()
  "Do complex stuff."
  (interactive)
  (goto-char (point-min))
  (save-excursion
    (query-replace-regexp
     (let ((patt `(regexp ,my-complex-pattern)))
       (rx-to-string `(: "a " ,patt "b " ,patt)))
     "x \\1 y \\2")))

As a side note, the documentation for beginning-of-buffer suggests using (goto-char (point-min)) instead of it when writing lisp.

  • Thanks for the elaborate answer! As I have little to no Lisp skill, I accepted @sds's answer for giving me the easy and "dirty" solution I was hoping for. You definitively also have my upvote, but I'll need to get to 15 points before you'll actually feel the effect. – Shylock May 18 '17 at 12:25
  • @Shylock Thanks for the appreciation. On the contrary, I think my answer is the "dirty" solution in this case, as sds correctly describes and gives pointers to the ideal way of doing things. This is why I upvoted that answer. I think the only advantage my answer has is that it involves a lower learning curve for someone unfamiliar with Elisp regexps. – Basil May 18 '17 at 14:27

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.