2

I'd like to define a function to do a query-replace-regexp with a pattern I often use. When not using capture groups, it works:

(defun my-replace ()
    (interactive)
    (query-replace-regexp "[[:nonascii:][:ascii:]]*xxx" "replacedText" nil (point-min) (point-max)))

But I couldn't figure out how to use capture groups -- neither '\(\)' nor '()' works:

(defun my-replace ()
  (interactive)
  (query-replace-regexp "([[:nonascii:][:ascii:]]*)xxx" "\1replacedText" nil (point-min) (point-max)))


(defun my-replace ()
    (interactive)
    (query-replace-regexp "\([[:nonascii:][:ascii:]]*\)xxx" "\1replacedText" nil (point-min) (point-max)))

But when invoked with M-x query-replace-regexp, \([[:nonascii:][:ascii:]]*\)xxx would work.

Meng Lu
  • 163
  • 6

2 Answers2

5

In Emacs Lisp string literals, backslash is an escape character. To express a single literal backslash character, as required by many regular expression constructs, you need two backslashes, eg:

"\\([[:nonascii:][:ascii:]]*\\)xxx"

You don't need the extra backslashes when you run query-replace-regexp interactively because you're not entering a string literal, ie, an Emacs Lisp language construct; you're entering the characters of the regexp directly.

Try hitting M-: (eval-expression) and entering this expression:

"\(foo\)"

You'll see:

"(foo)"

...indicating that an escaped parenthesis in a string literal is the same as an unescaped parenthesis. So the regular expression engine was seeing parentheses without a preceding backslash, which match only themselves; they weren't starting or ending a capturing group as you expected.

Sean
  • 929
  • 4
  • 13
  • That fixed it but it seems neither `\1` or `\\1` is working as the replacement part. – Meng Lu Jun 24 '15 at 07:41
  • Works for me with `"\\1replacedText"` as the replacement string. – Sean Jun 24 '15 at 07:50
  • Well explained, Sean. It is especially good that you mentioned why the extra backslashes are not used when interactive (not only not *needed*, but not usable, BTW). – Drew Jun 24 '15 at 13:44
  • `\\1` does work. It was a faulty regexp that caused me to think it didn't, – Meng Lu Jun 24 '15 at 17:29
3

Use "\" to quote "\":

(defun my-replace ()
  (interactive)
  (query-replace-regexp "\\([[:nonascii:][:ascii:]]*\\)xxx" "\\1replacedText"
                        nil (point-min) (point-max)))
xuchunyang
  • 14,302
  • 1
  • 18
  • 39