Perl, using tr function to convert uppercase to lowercase and vice-versa at the same time?

31.2k views Asked by At

I have a string

$string= 'AbCdEf';

and I want to use the tr function to convert all the uppercase letters to lower case and all the lower case to upper case.... at the same time. I basically just want to reverse it to become.

aBcDeF

I came up with this line, but I'm not sure how to modify it to do what I want. Any help please?

$string=~ tr/A-Z/a-z/;

Thanks!

3

There are 3 answers

3
friedo On BEST ANSWER

$string =~ tr/A-Za-z/a-zA-Z/;

3
hobbs On

At Tom's request, the Unicode-clean (or locales-clean) version:

s/([[:upper:]])|([[:lower:]])/defined $1 ? lc $1 : uc $2/eg
2
tchrist On

You can do the full Unicode solution either this way:

    s/ (\p{CWU}) | (\p{CWL}) /defined $1 ? uc $1 : lc $2/gex;

or this way

    s/ (\p{CWL}) | (\p{CWU}) /defined $1 ? lc $1 : uc $2/gex;

Depending on what you want to do with something that changes case in both directions, like Dz, whose uppercase is DZ and whose lowercase is dz.

If you run the second of those two substitutions across this input:

     @   0040  COMMERCIAL AT
     ©   00A9  COPYRIGHT SIGN
     Å   212B  ANGSTROM SIGN
     ⒜   249C  PARENTHESIZED LATIN SMALL LETTER A
     Ⓐ   24B6  CIRCLED LATIN CAPITAL LETTER A
     ⓐ   24D0  CIRCLED LATIN SMALL LETTER A
     A  FF21  FULLWIDTH LATIN CAPITAL LETTER A
     a  FF41  FULLWIDTH LATIN SMALL LETTER A
     Ⓒ   24B8  CIRCLED LATIN CAPITAL LETTER C
     ⓒ   24D2  CIRCLED LATIN SMALL LETTER C
     DZ   01F1  LATIN CAPITAL LETTER DZ
     Dz   01F2  LATIN CAPITAL LETTER D WITH SMALL LETTER Z
     dz   01F3  LATIN SMALL LETTER DZ
     ⅲ   2172  SMALL ROMAN NUMERAL THREE
     S   0053  LATIN CAPITAL LETTER S
     s   0073  LATIN SMALL LETTER S
     ſ   017F  LATIN SMALL LETTER LONG S
     ⒮   24AE  PARENTHESIZED LATIN SMALL LETTER S
     Ⓢ   24C8  CIRCLED LATIN CAPITAL LETTER S
     ⓢ   24E2  CIRCLED LATIN SMALL LETTER S
     Ꞅ   A784  LATIN CAPITAL LETTER INSULAR S
     ꞅ   A785  LATIN SMALL LETTER INSULAR S
     ß   00DF  LATIN SMALL LETTER SHARP S
     ẞ   1E9E  LATIN CAPITAL LETTER SHARP S
     Ⅶ   2166  ROMAN NUMERAL SEVEN
     ⅻ   217B  SMALL ROMAN NUMERAL TWELVE

it produces these results:

     @   0040  commercial at
     ©   00a9  copyright sign
     å   212b  angstrom sign
     ⒜   249c  parenthesized latin small letter a
     ⓐ   24b6  circled latin capital letter a
     Ⓐ   24d0  circled latin small letter a
     a  ff21  fullwidth latin capital letter a
     A  ff41  fullwidth latin small letter a
     ⓒ   24b8  circled latin capital letter c
     Ⓒ   24d2  circled latin small letter c
     dz   01f1  latin capital letter dz
     dz   01f2  latin capital letter d with small letter z
     DZ   01f3  latin small letter dz
     Ⅲ   2172  small roman numeral three
     s   0053  latin capital letter s
     S   0073  latin small letter s
     S   017f  latin small letter long s
     ⒮   24ae  parenthesized latin small letter s
     ⓢ   24c8  circled latin capital letter s
     Ⓢ   24e2  circled latin small letter s
     ꞅ   a784  latin capital letter insular s
     Ꞅ   a785  latin small letter insular s
     SS   00df  latin small letter sharp s
     ß   1e9e  latin capital letter sharp s
     ⅶ   2166  roman numeral seven
     Ⅻ   217b  small roman numeral twelve

The only part that would be different (in that set) using the first function would be that the dz sequence would then look like this instead:

     dz   01f1  latin capital letter dz
     DZ   01f2  latin capital letter d with small letter z
     DZ   01f3  latin small letter dz

The reason you don’t want to use just an upper or lower test is because then you do unnecessary work, since there are plenty of cased code points that do not change case when casemapped. All of these, for example, are cased code points but which change neither when uppercased nor when lowercased:

     ª   00AA FEMININE ORDINAL INDICATOR
     ᴬ   1D2C MODIFIER LETTER CAPITAL A
     ᴀ   1D00 LATIN LETTER SMALL CAPITAL A
     ℂ   2102 DOUBLE-STRUCK CAPITAL C
     ᴰ   1D30 MODIFIER LETTER CAPITAL D 
     ʣ   02A3 LATIN SMALL LETTER DZ DIGRAPH
     ʤ   02A4 LATIN SMALL LETTER DEZH DIGRAPH
     ℇ   2107 EULER CONSTANT
     ɘ   0258 LATIN SMALL LETTER REVERSED E
     ɞ   025E LATIN SMALL LETTER CLOSED REVERSED OPEN E
     ℊ   210A SCRIPT SMALL G
     ɡ   0261 LATIN SMALL LETTER SCRIPT G
     ɢ   0262 LATIN LETTER SMALL CAPITAL G
     ʰ   02B0 MODIFIER LETTER SMALL H
     ℋ   210B SCRIPT CAPITAL H
     ℎ   210E PLANCK CONSTANT 
     ℹ   2139 INFORMATION SOURCE
     ʲ   02B2 MODIFIER LETTER SMALL J
     ℳ   2133 SCRIPT CAPITAL M
     º   00BA MASCULINE ORDINAL INDICATOR
     ɸ   0278 LATIN SMALL LETTER PHI
     ĸ   0138 LATIN SMALL LETTER KRA
     ʏ   028F LATIN LETTER SMALL CAPITAL Y
     ℼ   213C DOUBLE-STRUCK SMALL PI

So you would detect that they were upper- or lowercase, then call the inverse mapping function, then discover that nothing at all had changed. I figure, why bother?