kevyt has asked for the wisdom of the Perl Monks concerning the following question:

I have a value that may be a letter followed by a 1 or 2. If the numebr is 1, I would like to make it a 2. If the number is 2, I would like to make it a 1. I can't seem to get it to work. I know there must be a simple way.
ex: A1 changed to A2 A2 changed to A1 Thanks $m = "A1"; or $m = "A2"; This wont work: $m =~ tr(/1/2/ | /2/1/); This works, but I dont like it: if ($m =~ /1/){ $machine =~ s/1/2/g; } else{ $m =~ s/2/1/g; }

Replies are listed 'Best First'.
Re: replace a digit with another digit
by davidrw (Prior) on Aug 17, 2005 at 18:46 UTC
    If you need to match against the letter as well, a regex like this will work:
    s/(?<=[a-zA-Z])[12]/ $& == 1 ? 2 : 1 /eg;
      Just as an aside, according to perlvar (about $&):
      The use of this variable anywhere in a program imposes a considerable performance penalty on all regular expression matches.


      It might be 'better' to do:
      s/(?<=[a-zA-Z])([12])/ $1 == 1 ? 2 : 1 /eg;
      (although I have to say I'm not sure why you'd need the positive look-behind instead of just a normal match?)
        heh. I had a capture and $1 in there orginally, and then to be 'clever' changed it to $& to save a couple characters :)

        As far as the positive look-behind, y, it's not necessary -- just (since it's zero-width) saves having to reference a second capture in the replacement:
        s/([a-z])([12])/ $1 . ($2 == 1 ? 2 : 1) /eig;
        (i think the /i is less efficient, too.. too many different ways to write this one)
Re: replace a digit with another digit
by Transient (Hermit) on Aug 17, 2005 at 18:43 UTC
    tr/// is insufficient because you want to match a letter followed by a number. I'm not sure if I've taken the best approach, but it's one way.
    #!/usr/bin/perl use strict; use warnings; my $string = "A1 and A2 but not 1 and 2"; my $switch_hash = { 1 => 2, 2 => 1 }; my $regexp = '([A-Za-z])('.(join( '|', keys %$switch_hash )).')'; print "Regexp: $regexp\n"; my $comp_regexp = qr"$regexp"; $string =~ s/$comp_regexp/$1.$switch_hash->{$2}/ge; print $string, "\n";
Re: replace a digit with another digit
by cowboy (Friar) on Aug 17, 2005 at 18:41 UTC
    You're on the right path with tr.
    $a = "A1"; $b = "B2"; printf("a: %s b: %s\n", $a, $b); $a =~ tr/[12]/[21]/; $b =~ tr/[12]/[21]/; printf("a: %s b: %s\n", $a, $b);

      tr/// is ok if it doesn't matter whether or not the digit follows an alpha character. He didn't specify whether this would be an issue or not; his discription of the problem was inadequate at explaining whether the alpha character plays a significant roll in determining whether or not to swap twos for ones and ones for twos.

      Your example with tr/[12]/[21]/; is in error, though. Technically it's not hurting anything to be substituting a [ character for another [ character, but it's pointless to do so. You might have been thinking that you needed to set up a character class within the tr/// operator. But tr/// doesn't use character classes, so [ and ] are seen as literal characters to be transliterated.

      It's also advisable to get in the habit of not using $a and $b, even in examples, since these variables (their global form) play a crucial role in sort. In the interest of avoiding confusion or difficult to track-down bugs, let sort have $a and $b. You can have your way with $c .. $z though. ;)


      Dave

        Agree'd on the $a/$b, and I see the point on the substitution. Thanks.