* Re: Transposing Regular Expression
2009-11-11 17:25 Transposing Regular Expression jrwats
@ 2009-11-11 20:51 ` harven
2009-11-11 21:45 ` Andreas Politz
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: harven @ 2009-11-11 20:51 UTC (permalink / raw)
To: help-gnu-emacs
jrwats <jrwats@gmail.com> writes:
> Perl provides the transpose operator:
> =~ tr/abc/xyz/ not really a regular expression, but exchanges 'x' for
> 'a', 'y' for 'b', and 'z' for 'c' in the source string.
>
> My question is how to accomplish this in emacs. When only needing to
> tranpose 2 characters that need to replace each other, (the equivalent
> perl expression woud be =~ tr/ab/ba/ as an example, I could simply
> regexp replace 'a' with a unique letter or symbol, maybe '$' for
> instance, then replace all b's with a's and all $'s with b's. This
> obviously becomes unweildy after we start transposing more than 2
> characters. My question is, now that emacs provides fancy regexp
> replace clauses: \# for the number match, and arbitrary lisp
> expressions \,(some-lisp), etc, is there a way to accomplish this in
> one fell swoop via a very crazy regular expression find-replace? Also
> is there a list of meaningful regular expression search escape
> characters somewhere (like \#) ?
The emacs manual gives the following snippet for swapping two values.
M-x replace-regexp <RET> \(x\)\|y <RET>
\,(if \1 "y" "x") <RET>
Note that you can swap two words by the same method. This is not exactly
what you are looking for though.
There are many functions that have been devised to swap values
according to an alist, e.g. for converting accents from iso8859-1 to html.
These can be easily adapted to get a command emulating tr.
Cheers
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Transposing Regular Expression
2009-11-11 17:25 Transposing Regular Expression jrwats
2009-11-11 20:51 ` harven
@ 2009-11-11 21:45 ` Andreas Politz
2009-11-12 6:40 ` LanX
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Andreas Politz @ 2009-11-11 21:45 UTC (permalink / raw)
To: help-gnu-emacs
jrwats <jrwats@gmail.com> writes:
> Perl provides the transpose operator:
> =~ tr/abc/xyz/ not really a regular expression, but exchanges 'x' for
> 'a', 'y' for 'b', and 'z' for 'c' in the source string.
>
> My question is how to accomplish this in emacs. When only needing to
> tranpose 2 characters that need to replace each other, (the equivalent
> perl expression woud be =~ tr/ab/ba/ as an example, I could simply
> regexp replace 'a' with a unique letter or symbol, maybe '$' for
> instance, then replace all b's with a's and all $'s with b's. This
> obviously becomes unweildy after we start transposing more than 2
> characters. My question is, now that emacs provides fancy regexp
> replace clauses: \# for the number match, and arbitrary lisp
> expressions \,(some-lisp), etc, is there a way to accomplish this in
> one fell swoop via a very crazy regular expression find-replace? Also
> is there a list of meaningful regular expression search escape
> characters somewhere (like \#) ?
You can use literal backreferences (e.g. \1) in the replacement part of
interactive uses of replace-regexp. Combine that with expressions \,
and you could write a c-compiler in emacs-regexp/elisp.
The regular expression syntax is described in the elisp manual.
(info "(elisp)Regular Expressions")
-ap
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Transposing Regular Expression
2009-11-11 17:25 Transposing Regular Expression jrwats
2009-11-11 20:51 ` harven
2009-11-11 21:45 ` Andreas Politz
@ 2009-11-12 6:40 ` LanX
2009-11-16 12:16 ` Andreas Röhler
[not found] ` <mailman.10804.1258373854.2239.help-gnu-emacs@gnu.org>
4 siblings, 0 replies; 7+ messages in thread
From: LanX @ 2009-11-12 6:40 UTC (permalink / raw)
To: help-gnu-emacs
Hi
I'm a newbie in elisp, but this works for me:
--------- tested in M-x ielm
ELISP> (defun pl-tr (STRING FROM TO)
"perlish transpose"
(replace-regexp-in-string
(concat "\[" FROM "\]")
(lambda (s)
(string (elt TO (search s FROM))))
STRING)
)
pl-tr
ELISP> (pl-tr "fedcba" "bcd" "BCD")
"feDCBa"
-----------------------------------------------
HTH
Cheers
Rolf
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Transposing Regular Expression
2009-11-11 17:25 Transposing Regular Expression jrwats
` (2 preceding siblings ...)
2009-11-12 6:40 ` LanX
@ 2009-11-16 12:16 ` Andreas Röhler
[not found] ` <mailman.10804.1258373854.2239.help-gnu-emacs@gnu.org>
4 siblings, 0 replies; 7+ messages in thread
From: Andreas Röhler @ 2009-11-16 12:16 UTC (permalink / raw)
To: jrwats; +Cc: help-gnu-emacs
jrwats wrote:
> Perl provides the transpose operator:
> =~ tr/abc/xyz/ not really a regular expression, but exchanges 'x' for
> 'a', 'y' for 'b', and 'z' for 'c' in the source string.
>
> My question is how to accomplish this in emacs. When only needing to
> tranpose 2 characters that need to replace each other, (the equivalent
> perl expression woud be =~ tr/ab/ba/ as an example, I could simply
> regexp replace 'a' with a unique letter or symbol, maybe '$' for
> instance, then replace all b's with a's and all $'s with b's. This
> obviously becomes unweildy after we start transposing more than 2
> characters. My question is, now that emacs provides fancy regexp
> replace clauses: \# for the number match, and arbitrary lisp
> expressions \,(some-lisp), etc, is there a way to accomplish this in
> one fell swoop via a very crazy regular expression find-replace? Also
> is there a list of meaningful regular expression search escape
> characters somewhere (like \#) ?
>
IIUC you are going to change strings.
That's a simple task then with no need to employ
\# for the number match ore other advanced features.
Interactivly just call
M-x query-replace - putting in your strings at the prompt.
From a program use for example
(while
(search-forward "abc" nil t 1)
(replace-match "xyz"))
Andreas
--
https://code.launchpad.net/s-x-emacs-werkstatt/
http://bazaar.launchpad.net/~a-roehler/python-mode/python-mode.el/
^ permalink raw reply [flat|nested] 7+ messages in thread
[parent not found: <mailman.10804.1258373854.2239.help-gnu-emacs@gnu.org>]
* Re: Transposing Regular Expression
[not found] ` <mailman.10804.1258373854.2239.help-gnu-emacs@gnu.org>
@ 2009-11-16 16:28 ` jrwats
2009-11-17 2:13 ` LanX
0 siblings, 1 reply; 7+ messages in thread
From: jrwats @ 2009-11-16 16:28 UTC (permalink / raw)
To: help-gnu-emacs
> IIUC you are going to change strings.
>
> That's a simple task then with no need to employ
> \# for the number match ore other advanced features.
>
> Interactivly just call
>
> M-x query-replace - putting in your strings at the prompt.
>
> From a program use for example
>
> (while
> (search-forward "abc" nil t 1)
> (replace-match "xyz"))
That's not exactly what I'm looking for as I really need 2 words/
characters to be swapped. For instance, swapping "true" and "false"
in a region. Replacing all the "true"s with "false"s will yield a 1/2
correct answer but there's no way to replace the old false's anymore.
LanX's solution appears to do the correct thing regarding an actual
Perl-style transpose, and seeems like it could easily be altered to
work on a region. The quickest solution for the simple 2-way swap was
definitely the back reference (example provided by harven).
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Transposing Regular Expression
2009-11-16 16:28 ` jrwats
@ 2009-11-17 2:13 ` LanX
0 siblings, 0 replies; 7+ messages in thread
From: LanX @ 2009-11-17 2:13 UTC (permalink / raw)
To: help-gnu-emacs
> That's not exactly what I'm looking for as I really need 2 words/
> characters to be swapped. For instance, swapping "true" and "false"
> in a region.
OK let's talk perl to understand ... Thats what you want?
perl -e '
$_="EXAMPLE true EXAMPLE false EXAMPLE";
%trans=(true=>"false");
%trans=(%trans,reverse %trans);
$pattern=join "|",keys %trans;
s/($pattern)/$trans{$1}/g;
print "OUTPUT: $_";
'
OUTPUT: EXAMPLE false EXAMPLE true EXAMPLE
(please note: if you don't just want a dual swap but a more
complicated permutation, skip the "reverse" part and provide %trans as
needed like e.g. (1=>2, 2=>3, 3=>1))
You can easily adjust the lisp code I gave you to do that, you need to
change the lambda to do a hash look up and call it within one of the
region-replace functions!
Though for me the corresponding lisp code for hashes seem a little
lengthy...
(I now there are alists, but I leave this solution to others)
So why don't you just pipe a region thru the perl script above?
Typing
C-u M-|
perl -pe '
%trans=(true=>"false");
%trans=(%trans,reverse %trans);
$pattern=join "|",keys %trans;
s/($pattern)/$trans{$1}/g;
'
Can be easily adjusted to do what you want.
And if you type C-x ESC ESC you get the corresponding lisp wrapper for
free
---------
(shell-command-on-region (region-beginning) (region-end) "perl -pe '
%trans=(true=>\"false\");
%trans=(%trans,reverse %trans);
$pattern=join \"|\",keys %trans;
s/($pattern)/$trans{$1}/g;
'
" (quote -) (quote -) nil t)
--------
Couldn't be easier... and the call overhead to perl is really not
observable...
HTH
LanX
^ permalink raw reply [flat|nested] 7+ messages in thread