8

If you have a simple regex replace in perl as follows:

($line =~ s/JAM/AAA/g){

how would I modify it so that it looks at the match and makes the replacement the same case as the match for example:

'JAM' would become 'AAA' and 'jam' would become 'aaa'

MarcoS
  • 13,386
  • 7
  • 42
  • 63
ar.dll
  • 767
  • 4
  • 16
  • 35

4 Answers4

4

Unicode-based solution:

use Unicode::UCD qw(charinfo);
my %category_mapping = (
    Lu  # upper-case Letter
        => 'A',
    Ll  # lower-case Letter
        => 'a',
);

join q(), map { $category_mapping{charinfo(ord $_)->{category}} } split //, 'jam';
# returns aaa

join q(), map { $category_mapping{charinfo(ord $_)->{category}} } split //, 'JAM';
# returns AAA

Here the unhandled characters resp. their categories are a bit easier to see than in the other answers.

daxim
  • 39,270
  • 4
  • 65
  • 132
3

In Perl 5 you can do something like:

$line =~ s/JAM/$_=$&; tr!A-Z!A!; tr!a-z!a!; $_/gie;

It handles all different cases of JAM, like Jam, and it's easy to add other words, eg:

$line =~ s/JAM|SPAM/$_=$&; tr!A-Z!A!; tr!a-z!a!; $_/gie;
Qtax
  • 33,241
  • 9
  • 83
  • 121
  • Telling us how to handle non-uniform targets (eg `s/jam/stuck/`) would be more interesting than how to handle multiple sources (Or perhaps to make it easier, `s/jam/mit/`) – Seth Robertson Jun 08 '11 at 15:05
  • I'm curious - in these examples where is the actual string to replace with specified? – ar.dll Jun 08 '11 at 15:05
  • @r4d2: He took advantage that the target was uniform 'A's, `tr/A-Z/A/' translates JAM to AAA. That is why I posted my follow-up as a more general case. – Seth Robertson Jun 08 '11 at 15:10
  • @4rd2, it's not. I'm just using `tr///` to replace all upper case letters to `A` and all lower to `a` – Qtax Jun 08 '11 at 15:11
  • @Seth, what special treatment would you want from `s/jam/stuck/` anyway? Upper to upper, lower to lower? And what about `jaM`? – Qtax Jun 08 '11 at 15:14
  • @Qtax: That is why I edited my comment to be `s/jam/mit/` to have the same number of letters. Presumably `jaM` should go to `miT`. Bonus points if it handles `s/jam/mom/`. – Seth Robertson Jun 08 '11 at 15:17
  • @Seth, that's no problem, only complication would be `s/mam/mit/` – Qtax Jun 08 '11 at 15:26
2

Something like this perhaps?

http://perldoc.perl.org/perlfaq6.html#How-do-I-substitute-case-insensitively-on-the-LHS-while-preserving-case-on-the-RHS%3f

Doing it in two-steps is probably a better/simpler idea...

Using the power of google I found this

The :samecase modifier, short :ii (since it's a variant of :i) preserve case.

    my $x = 'Abcd';
    $x ~~ s:ii/^../foo/;
    say $x;                     # Foocd
    $x = 'ABC'
    $x ~~ s:ii/^../foo/;
    say $x                      # FOO

This is very useful if you want to globally rename your module Foo, to Bar,
but for example in environment variables it is written as all uppercase.
With the :ii modifier the case is automatically preserved.
Fredrik Pihl
  • 44,604
  • 7
  • 83
  • 130
1
$line =~ s/JAM/{$& eq 'jam' ? 'aaa' : 'AAA'}/gie;
Blagovest Buyukliev
  • 42,498
  • 14
  • 94
  • 130
  • 1
    This does not handle `Jam` -> `Aaa` – MarcoS Jun 08 '11 at 14:44
  • 2
    Also it's kinda pointless to use regex if you afterwards compare to fixed strings… – Tomalak Jun 08 '11 at 14:46
  • Amazing! thats it :) is that basically like an if statement inside the {} ? – ar.dll Jun 08 '11 at 14:53
  • 1
    @4rd2, the {} is useless in this case. Also see my example. ;) – Qtax Jun 08 '11 at 14:55
  • Tomalak - what do you mean? in the example I'm just doing a literal find and replace? doesn't matter about 'Jam' 'Aaa' MacroS for the paticular application I'm using it in :) would be good to know though ;) – ar.dll Jun 08 '11 at 14:57