Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

query-replace-regexp-swap ?

5 views
Skip to first unread message

Bastien

unread,
Nov 23, 2005, 9:10:40 PM11/23/05
to
I often come across this problem: how to swap two strings in a buffer?
For instance, say that you want to exchange #000 and #FFF in an HTML
page: all #000 should become #FFF and all #FFF should become #000.

How to do this with one *single* function ?

For now i use this:

==%<==================================================================
(defun query-replace-regexp-swap (regexp-a regexp-b beg end)
"Swap A and B strings in the selected region."
(interactive
(let ((regexp-a (read-string "Regexp A: "))
(regexp-b (read-string "Regexp B: ")))
(list regexp-a regexp-b (region-beginning) (region-end))))
(save-match-data
(save-excursion
(goto-char beg)
(let* ((regexp (concat "\\(" regexp-a "\\)\\|"
"\\(" regexp-b "\\)"))
(match-a (save-excursion
(re-search-forward regexp-a end t)
(match-string 0)))
(match-b (save-excursion
(re-search-forward regexp-b end t)
(match-string 0))))
(while (re-search-forward regexp nil t)
(cond ((match-string 1)
(when (y-or-n-p (format "Replace with %s? " match-b))
(replace-match match-b t t)))
((match-string 2)
(when (y-or-n-p (format "Replace with %s? " match-a))
(replace-match match-a t t)))))))))
======================================================================

... which is quite UGLY.

Any idea on how to use `perform-replace' to achieve this in a more
efficient way?

--
Bastien

rgb

unread,
Nov 25, 2005, 9:03:18 PM11/25/05
to

Bastien wrote:
> I often come across this problem: how to swap two strings in a buffer?
> For instance, say that you want to exchange #000 and #FFF in an HTML
> page: all #000 should become #FFF and all #FFF should become #000.
>
> How to do this with one *single* function ?
>
> For now i use this:
>
> ==%<==================================================================
> (defun query-replace-regexp-swap (regexp-a regexp-b beg end)...

Does this look like what you wanted?

(defun swap-text (str1 str2 beg end)
"Changes all STR1 to STR2 and all STR2 to STR1"
(interactive "sString A: \nsString B: \nr")
(goto-char beg)
(while (re-search-forward
(concat "\\(?:\\(" (regexp-quote str1) "\\)\\|\\("
(regexp-quote str2) "\\)\\)") end t)
(if (match-string 1)
(replace-match str2 t t)
(replace-match str1 t t))))

Bastien

unread,
Nov 25, 2005, 10:54:01 PM11/25/05
to
"rgb" <rbie...@i1.net> writes:

> Does this look like what you wanted?
>
> (defun swap-text (str1 str2 beg end)

Well, kind of.

The thing is that i rather would like to use regexps (instead of meer
strings), and i would like this func to behave like query-* functions
- i.e. asking for each instance etc, since this function would often
be called in a context where we just *don't* want each occurrence to
be replaced.

But i don't know if it's possible, or even a good idea to try to use
perform-replace for this purpose.

Anyway, thanks for the help!

--
Bastien

David Kastrup

unread,
Nov 26, 2005, 1:14:44 AM11/26/05
to
Bastien <bas...@xxx.fr> writes:

> I often come across this problem: how to swap two strings in a buffer?
> For instance, say that you want to exchange #000 and #FFF in an HTML
> page: all #000 should become #FFF and all #FFF should become #000.
>
> How to do this with one *single* function ?

If you are using Emacs CVS (which your headers indicate), the
following should do the trick:

C-M-% #\(\(000\)\|FFF\) RET \,(if &2 "FFF" "000") RET

If you want to know how to do this non-interactively, type
C-x ESC ESC
after the above command.

--
David Kastrup, Kriemhildstr. 15, 44793 Bochum

David Kastrup

unread,
Nov 26, 2005, 1:22:03 AM11/26/05
to

[Superseded because of syntax error]

Bastien <bas...@xxx.fr> writes:

> I often come across this problem: how to swap two strings in a buffer?
> For instance, say that you want to exchange #000 and #FFF in an HTML
> page: all #000 should become #FFF and all #FFF should become #000.
>
> How to do this with one *single* function ?

If you are using Emacs CVS (which your headers indicate), the


following should do the trick:

C-M-% #\(\(000\)\|FFF\) RET \,(if \2 "FFF" "000") RET

Bastien

unread,
Nov 28, 2005, 7:59:36 AM11/28/05
to
David Kastrup <d...@gnu.org> writes:

> If you are using Emacs CVS (which your headers indicate), the
> following should do the trick:
>
> C-M-% #\(\(000\)\|FFF\) RET \,(if \2 "FFF" "000") RET

^

(I guess the "#" above was just a typo.)

Great! Works like a charm.

Thanks a lot,

--
Bastien

David Kastrup

unread,
Nov 28, 2005, 8:35:45 AM11/28/05
to
Bastien <bas...@xxx.fr> writes:

> David Kastrup <d...@gnu.org> writes:
>
>> If you are using Emacs CVS (which your headers indicate), the
>> following should do the trick:
>>
>> C-M-% #\(\(000\)\|FFF\) RET \,(if \2 "FFF" "000") RET
> ^
>
> (I guess the "#" above was just a typo.)

Uh, no. You asked for replacing #000 and #fff, so the # needs to get
matched. The error in the above is not that the # is in the match
string, but that it is missing in the replacement.

Bastien

unread,
Nov 28, 2005, 8:54:33 AM11/28/05
to
David Kastrup <d...@gnu.org> writes:

>> (I guess the "#" above was just a typo.)
>
> Uh, no. You asked for replacing #000 and #fff, so the # needs to
> get matched. The error in the above is not that the # is in the
> match string, but that it is missing in the replacement.

Right, no problem.

Now i'm using this:

,----
| (defun query-swap-regexp (regexp-a regexp-b)
| "Swap A and B regexp matches in current buffer or region."
| (interactive "sRegexp A: \nsRegexp B: ")
| (let ((match-a (save-excursion
| (re-search-forward regexp-a nil t)
| (match-string 0)))
| (match-b (save-excursion
| (re-search-forward regexp-b nil t)
| (match-string 0))))
| (query-replace-regexp
| (concat "\\(\\(" regexp-a "\\)\\|" regexp-b "\\)")
| `(replace-eval-replacement
| replace-quote
| (if (match-string 2) ,match-b ,match-a))
| nil
| (if (and transient-mark-mode mark-active) (region-beginning))
| (if (and transient-mark-mode mark-active) (region-end)))))
`----

It prompts for two regexps, find the first occurrence of each one and
query-replace all occurrences. This is what i need in most cases.

The limitation concerns match-a and match-b, which are defined once
and for all. But it seems to me that other behaviors would be quite
non-intuitive and tricky.

--
Bastien

0 new messages