23
\$\begingroup\$

Given a non‑empty string containing only printable ASCII (codepoints 0x20 to 0x7E), write the shortest program or function that swaps the cases of A-Z and a-z.

  • If a character is in [A-Z], convert it to its lowercase version.
  • If a character is in [a-z], convert it to its uppercase version.
  • Otherwise, leave the character alone.

Test Cases

input output
abc ABC
ABC abc
Mixed Case mIXED cASE
1234 1234
123#$%hIjK456 123#$%HiJk456
\$\endgroup\$
2
  • 2
    \$\begingroup\$ I don't consider this a dup of the other case swapping challenges because the others (such as codegolf.stackexchange.com/q/36802/77309) are X-without-Y challenges, which this isn't. \$\endgroup\$
    – bigyihsuan
    Feb 22 at 18:19
  • 2
    \$\begingroup\$ I would consider it a dupe, but I closed the other question instead since its restrictions are really unclear, and this is clearly the higher quality question. \$\endgroup\$
    – Wheat Wizard
    Feb 23 at 17:29

41 Answers 41

10
\$\begingroup\$

MATL, 2 bytes

Yo

Try it at MATL online!

\$\endgroup\$
1
  • 10
    \$\begingroup\$ Yo!! also works and is perhaps more idiomatic \$\endgroup\$
    – Luis Mendo
    Feb 22 at 18:36
7
\$\begingroup\$

Python 3, 47 bytes

lambda s:[chr(ord(c)^32*c.isalpha())for c in s]

Try it online!

\$\endgroup\$
3
  • 1
    \$\begingroup\$ 51 bytes \$\endgroup\$
    – enzo
    Feb 22 at 18:45
  • 2
    \$\begingroup\$ 47 bytes if returning a list is fine (since you used map originally) \$\endgroup\$
    – enzo
    Feb 22 at 18:47
  • 2
    \$\begingroup\$ @enzo Nice trick there multiplying 32 by c.isalpha() to make it zero. \$\endgroup\$ Feb 22 at 18:54
6
\$\begingroup\$

C (gcc), 40 bytes

f(char*s){if(*s^=isalpha(*s)/32)f(s+1);}

Try it online!

C (gcc), 45 42 bytes

f(char*s){if(*s^=isalpha(*s)?32:0)f(s+1);}

Try it online!

\$\endgroup\$
5
\$\begingroup\$

Python, 12 bytes

str.swapcase

Attempt This Online! (Python 3)
Attempt This Online! (Python 2)

Pyth, 3 bytes

rQ2

Attempt This Online!

 Q    # input
r 2   # swapcase
\$\endgroup\$
5
\$\begingroup\$

K (ngn/k), 20 bytes

{`c$(_x)-32*~"a{"'x}

Try it online!

Lowercase the entire string using the builtin _ and then subtract 32 from those that were already lowercase to make them uppercase.

{`c$(_x)-32*~"a{"'x}    x: string
             "a{"'x     for each char c in x, -1 if c<'a', 0 if 'a'<=c<'{',
                        1 if '{'<=c
         32*~           boolean not times 32; gives 32 for lowercase in input
    (_x)                lowercase version of x
        -               subtract to uppercase the lowercase
 `c$                    convert the result of arithmetic back to char type
\$\endgroup\$
5
\$\begingroup\$

R, 31 bytes

\(s)chartr("a-zA-Z","A-Za-z",s)

Attempt This Online!

\$\endgroup\$
1
  • \$\begingroup\$ Another day, another R function I've never seen before! \$\endgroup\$
    – qwr
    Feb 23 at 21:25
5
\$\begingroup\$

V (vim), 2 bytes

V~

Try it online!

\$\endgroup\$
5
\$\begingroup\$

Bash + coreutils, 16 bytes

Exactly what tr is for.

tr A-Za-z a-zA-Z

Attempt This Online!

\$\endgroup\$
2
  • \$\begingroup\$ 11 bytes. -5 bytes by using the Bash ~~ operator instead of tr translate method. \$\endgroup\$
    – vengy
    Feb 25 at 12:57
  • \$\begingroup\$ @vengy your answer is fundamentally different enough to not be a modification of this one \$\endgroup\$
    – qwr
    Feb 25 at 17:34
5
\$\begingroup\$

Bash, 11 bytes

The ~~ operator in Bash can be used to toggle the case of all characters in a string.

echo ${1~~}

Try it online!

\$\endgroup\$
5
  • \$\begingroup\$ I'm pretty sure that this breaks at least one standard loophole. \$\endgroup\$
    – Neil
    Feb 24 at 19:54
  • \$\begingroup\$ If you introduce input that's not part of the question, you have to include it in the answer. Then it is pretty much a copy of my answer. \$\endgroup\$
    – qwr
    Feb 24 at 22:43
  • 1
    \$\begingroup\$ @Neil The answer has been updated to close any standard loophole and is now shorter using the ~~ operator instead of the longer tr method. Thanks. \$\endgroup\$
    – vengy
    Feb 25 at 13:28
  • \$\begingroup\$ You're still reading input from the predefined variable $s instead of, say, an argument $1 which would work just as well for the same byte count and has the advantage of being an acceptable input format. \$\endgroup\$
    – Neil
    Feb 25 at 14:28
  • \$\begingroup\$ @Neil Nice! Thanks for the tip about using $1 instead of $s. Works great now and occupies the same number of bytes too. \$\endgroup\$
    – vengy
    Feb 25 at 14:48
5
\$\begingroup\$

JavaScript (ES6), 56 bytes

-5 thanks to @ngn

s=>s.replace(/./g,c=>c[`to${c<{}?'Low':'Upp'}erCase`]())

Try it online!


JavaScript (Node.js), 45 bytes

-6 thanks to @ngn

s=>Buffer(s).map(c=>c^32*(c>>6&--c%32<26))+""

Try it online!

\$\endgroup\$
3
  • 2
    \$\begingroup\$ why not /./g (instead of /[a-z]/gi) for es6? \$\endgroup\$
    – ngn
    Feb 25 at 14:16
  • 1
    \$\begingroup\$ shorter for node.js: s=>Buffer(s).map(c=>c^32*(c>>6&--c%32<26))+'' \$\endgroup\$
    – ngn
    Feb 27 at 0:05
  • \$\begingroup\$ 42 \$\endgroup\$
    – l4m2
    Mar 27 at 9:28
4
\$\begingroup\$

Acc!!, 59 bytes

N
Count i while _ {
Write _+_/65*(90/_-_/97*(122/_))*32
N
}

Try it online!

Explanation

Here's a slightly de-obfuscated version:

N
Count i while _ {
  Write _ + (_/65)*(90/_)*32 - (_/97)*(122/_)*32
  N
}

N reads a character of input and stores its ASCII code in the accumulator.

Count i while _ loops while the accumulator's value is nonzero. After the end of input (including an implicit trailing newline), N returns zero, so this loops over the entire input and then halts.

Acc!! doesn't have comparison operators, so we use integer division to determine what range a character code is in:

_/65 90/_ _/97 122/_ Range
0 >= 1 0 >= 1 _ < A
1 1 0 1 A ≤ _ ≤ Z
1 0 0 1 Z < _ < a
1 0 1 1 a ≤ _ ≤ z
1 0 1 0 z < _

Multiplying the first two tells us the character is uppercase, in which case we add 32 to make it lowercase. Multiplying the second two tells us the character is lowercase, in which case we subtract 32 to make it uppercase. We then Write out the modified character and read another one with N.

For the golfed version, we pull the common factor of 32 out of both products, and then observe that _/65 can only ever be 0 or 1, and it's only 0 when we don't want to modify the character, so it can be pulled out as well.

\$\endgroup\$
4
\$\begingroup\$

J, 16 14 bytes

3!:12"+~'`'&I.

NOTE: fails on ATO's older J but works in j9.4.2

-9 thanks to ovs!!

-2 thanks to Bubbler for a very nice refinement!

The basic clever idea is due to ovs. The idea to simplify it using "insert before" to get the upper/lower flags '`'&I. is due to Bubbler.

  • 3!:12 is the J verb for changing case -- a 0 left arg makes it downcase and a 1 makes it upcase. We add "+ to change the rank and make it work on atoms.
  • ~'`'&I. Returns a boolean array with zeros where the input is less than ` (lowercase), and ones elsewhere (uppercase).
  • That boolean array, in its entirety, is the left arg to 3!:12, and the original input is the right arg. Since we are operating on atoms, it flips the case of each letter.

J, 24 bytes

g`tolower@.(=g=.toupper)

Attempt This Online!

-1 thanks to ovs for this variant using agenda!

This showcases an interesting fact about agenda, which is that if you provide it a list of integers, it runs on each on separately, returning a list of results.

So it applies 'tolower' to every uppercase letter, and toupper to every lowercase one.

J, 27 25 bytes (original)

(=0{g)`(g=.3!:12"{~&0 1)}

Attempt This Online! (NOTE: fails on ATO's older J but works in j9.4.2)

29 byte variant that works on ATO:

(=0{g)`(g=.tolower,:toupper)}

The variant is clearer for the explanation anyway:

  • (...)`(...)} A single application of the rarely used Item Amend.

  • g=.tolower,:toupper Construct all lowercase and all uppercase versions of the input:

    mixed case
    MIXED CASE
    
  • =0{g Boolean vector showing where the input is lowercase:

    0 1 1 1 1 1 0 1 1 1
    
  • Item amend then takes from the uppercase version at each 1 index, and from the lowercase version at each 0 index.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Using Agenda gets close for a variant working on older versions: 26. Actually, omitting the "0 still works, so it's 24. Didn't know Agenda worked that way. \$\endgroup\$
    – ovs
    Feb 22 at 22:05
  • 1
    \$\begingroup\$ And I think (=0&g)(g=.3!:12"+)] works. ... and q~]=0&q=.3!:12"+ \$\endgroup\$
    – ovs
    Feb 22 at 22:11
  • \$\begingroup\$ oh my... q~]=0&q=.3!:12"+ is brilliant \$\endgroup\$
    – Jonah
    Feb 22 at 22:30
  • 1
    \$\begingroup\$ 14 bytes: 3!:12"+~'`'&I. - toupper for characters of a or higher, tolower otherwise. \$\endgroup\$
    – Bubbler
    Feb 23 at 5:01
  • \$\begingroup\$ @Bubbler That is very nice use of insert before. \$\endgroup\$
    – Jonah
    Feb 23 at 5:32
3
\$\begingroup\$

Uiua SBCS, 1 byte

¯

Try it on Uiua pad!

\$\endgroup\$
3
\$\begingroup\$

Perl 5 -p, 14 bytes

s/\pL/$&^$"/ge

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Excel, 71 bytes

=LET(c,MID(A1,ROW(A:A),1),d,LOWER(c),CONCAT(IF(EXACT(c,d),UPPER(c),d)))

Input is in the cell A1. Output is wherever the formula is. I feel like there should be a shorter way to do this but Excel is limited in its case-switching functions.

The LET() function allows you to define variable as a name,value pair. This saves us bytes by letting us reference data by a shorter name.

  • c,MID(A1,ROW(A:A),1) breaks the input into individual characters. In the latest versions of Excel, ROW(A:A) will have a max value of 2^20 and the characters in a cell are limited to 2^15 so this will cover all cases.
  • d,LOWER(c) converts each character into its lowercase regardless of how it started.
  • CONCAT(IF(EXACT(c,d),UPPER(c),d)) checks each original character to see if it matches the lowercase version and, if it does, returns the uppercase version. Otherwise, it returns the lowercase. We have to use EXACT() because c=d is case-insensitive. The CONCAT() parts just re-combines all those individual characters into a single string.

Screenshot

\$\endgroup\$
3
\$\begingroup\$

Java 10, 64 bytes

s->{for(var c:s)System.out.print(c>64&c<91|c>96&c<123?c^=32:c);}

Input as a character-array; output is printed directly to STDOUT.

Try it online.

Explanation:

s->{                  // Method with character-array parameter and no return
  for(var c:s)        //  Loop over the characters of the input:
    System.out.print( //   Print:
      c>64&c<91|c>96&c<123?
                      //    If the character is a letter:
       c^=32          //     Invert its case by XOR-ing the codepoint by 32 (the `^=`
                      //     instead of `^` is so it'll remain a character instead of
                      //     becoming an integer)
      :               //    Else (it's not a letter):
       c);}           //     Print the character as is
\$\endgroup\$
3
\$\begingroup\$

Haskell + hgl, 16, 12 bytes

m$TL?.TU~<iU

Attempt This Online!

Thanks to Bubbler's comment on a different post for helping me realize how to take 4 bytes off

Explanation

This is really simple. m maps across a string iU checks if a character is uppercase, TU makes a character uppercase TL makes it lowercase.

Using parsers, 22 bytes

gk$my$(TL<pU)#|(TU<hd)

Attempt This Online!

Reflection

It's really weird that the main answer uses basically no function composition, and the only infix function it uses is function application, especially considering it uses 6 functions in total. However the l3 is still glue, and is clearly costing more than it should. I golfed away the l3 now, which is good.

The parser version is never going to be competitive for this challenge, but I did it anyway to get practice with that part of the library. 22 bytes is not awful, I don't think, but it could probably be improved.

  • A case swap builtin would probably be good. It seems weird and niche, but I can see how this is can actually be useful in odd ways, and apparently both Vyxal and Python have it as builtins.
  • l3 iF is probably worth having, plus a version that only lifts over the first two arguments.
  • l3 could have an infix version. Even at 3 bytes, this would save bytes.
  • The tr function that I see other people using seems like it could be helpful in general, although it's unlikely it would ever be the way to go for this answer. Best case scenario is 15 bytes.
  • Maybe something that combines gk and gMy would be useful. "Apply this parser as many times as it takes to finish the string".
  • A shortcut for fm hd, parse a character and apply a function, would probably be good.
\$\endgroup\$
3
\$\begingroup\$

K (ngn/k), 27 26 24 bytes

-1 byte thanks to @akamayu and another -1 thanks to @ngn!

ngn/K has a builtin for converting to lower case (_), but none for converting to uppercase, so there has to be some sort of codepoint arithmetic involved.

`c$32/|(0/2\1-"A[a{"')'\

Try it online!

\$\endgroup\$
6
  • 2
    \$\begingroup\$ From the first alternative, by changing -1+ to 1- and -32 to +32, we have {`c$x+32*a*2!a:1-"A[a{"'x}, saving a byte. \$\endgroup\$
    – akamayu
    Feb 23 at 6:07
  • \$\begingroup\$ building up on this solution: you can save a couple more bytes by encoding the index in binary and multiplying its bits together: {`c$x-32*/2\" A[a{"'x} - here uppercase and lowercase correspond to 1 and 3, and they happen to be the only valid indices whose product of bits is 1 \$\endgroup\$
    – ngn
    Feb 25 at 16:57
  • \$\begingroup\$ @ngn I don't think that works. We need to add 32 for uppercase letters, but 32*/2\... is never negative. \$\endgroup\$
    – ovs
    Feb 25 at 17:08
  • 1
    \$\begingroup\$ just one byte shorter: ``` `c${x+32*0/2\1-"A[a{"'x}' ``` (and hopefully correct this time) \$\endgroup\$
    – ngn
    Feb 25 at 17:18
  • 1
    \$\begingroup\$ @ngn yes that works, thanks. was able to get rid of another byte by going full tacit \$\endgroup\$
    – ovs
    Feb 25 at 17:33
2
\$\begingroup\$

Vyxal 3, 1 byte

N

Try it Online!

\$\endgroup\$
2
\$\begingroup\$

TypeScript’s type system, 141 bytes

141 bytes with capitalization builtins:

type G<C,U=Uppercase<C>,L=Lowercase<C>>=U extends L?C:C extends U?L:U
type F<S,O>=S extends`${infer C}${infer S}`?F<S,`${O&string}${G<C>}`>:O

186 bytes no builtins:

type F<S,O>=S extends`${infer C}${infer S}`?F<S,`${O&string}${"aAabBbcCcdDdeEefFfgGghHhiIijJjkKklLlmMmnNnoOopPpqQqrRrsSstTtuUuvVvwWwxXxyYyzZz"extends`${any}${C}${infer c}${any}`?c:C}`>:O
\$\endgroup\$
2
\$\begingroup\$

APL (Dyalog APL), 13 12 bytes

⊢⎕C¨⍨¯1*⎕C≠⊢

Attempt This Online!

⊢⎕C¨⍨¯1*⎕C≠⊢­⁡​‎‎⁡⁠⁣⁤‏‏​⁡⁠⁡‌⁢​‎‎⁡⁠⁣⁣‏‏​⁡⁠⁡‌⁣​‎‎⁡⁠⁣⁡‏⁠‎⁡⁠⁣⁢‏‏​⁡⁠⁡‌⁤​‎‎⁡⁠⁢⁢‏⁠‎⁡⁠⁢⁣‏⁠‎⁡⁠⁢⁤‏‏​⁡⁠⁡‌⁢⁡​‎‎⁡⁠⁢‏⁠‎⁡⁠⁣‏⁠‎⁡⁠⁤‏⁠‎⁡⁠⁢⁡‏‏​⁡⁠⁡‌⁢⁢​‎‎⁡⁠⁡‏‏​⁡⁠⁡‌­
           ⊢  # ‎⁡input
          ≠   # ‎⁢not equal to (vectorized)
        ⎕C    # ‎⁣lowercase version
     ¯1*      # ‎⁤-1 ^ x (convert 0 to 1, 1 to -1)
 ⎕C¨⍨         # ‎⁢⁡convert to uppercase where 1 and lowercase where -1
⊢             # ‎⁢⁢on input
💎

Created with the help of Luminespire.

APL (Dyalog Extended), 1 byte

-

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Haskell, 64 58 bytes

-6 bytes thanks to Bubbler.

import Data.Char
f s=[last(toUpper:[toLower|c<'a'])c|c<-s]

Try it online!

I wish there were a more interesting solution but it probably looks like:

85 bytes

f s=[last$c:[toEnum$o-(signum$o-91)*32|64<o&&o<91||96<o&&o<123]|c<-s,o<-[fromEnum c]]

Try it online!

...Yeah. Gross. There's also:

98 bytes

f s=[last$c:[n|(Just n)<-[m]]|c<-s,m<-[lookup c$zip['a'..'z']['A'..'Z']++zip['A'..'Z']['a'..'z']]]

Try it online!

I feel like this could get a whole lot better but I'm blanking.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ 58: import Data.Char;f s=[last(toUpper:[toLower|c<'a'])c|c<-s]. There's a cool pointfree version map$bool toUpper toLower=<<(<'a') but costs an extra import Data.Bool so is slightly longer. \$\endgroup\$
    – Bubbler
    Feb 23 at 5:50
  • \$\begingroup\$ 56 bytes \$\endgroup\$
    – Wheat Wizard
    Feb 24 at 20:20
  • \$\begingroup\$ @Bubbler For the pointfree version it's slightly shorter to just implement bool as an infix than to import it, but not enough to compete with the pointful versions. \$\endgroup\$
    – Wheat Wizard
    Feb 24 at 20:22
2
\$\begingroup\$

MathGolf, 7 bytes

ô∙!=¿δ!

Try it online.

Explanation:

ô       # Loop over the characters of the (implicit) input-string,
        # using the following 6 characters as inner code-block:
 ∙      #  Triplicate the current character
  !     #  Lowercase the top copy
   =    #  Pop the top two, and check whether they're still equal
    ¿   #  If they were equal (aka the character was lowercase, or not a letter):
     δ  #   Uppercase the character
    ¿   #  Else (it was an uppercase character)
     !  #   Lowercase the character instead
        # (after the loop, the entire stack is joined together and output implicitly)
\$\endgroup\$
2
\$\begingroup\$

Japt v2.0a0, 7 bytes

r\lÈc^H

Try it

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Ugh, so obvious now! Nice \$\endgroup\$
    – noodle man
    Feb 23 at 23:55
2
\$\begingroup\$

Labyrinth, 41 bytes

" @
,::4/*_
. _6  "
$*  %23
326#(
_ /
%#)

Try it online!

Labyrinth doesn't have any built-ins related to letter case, and making multiple if-branches is incredibly wacky. Fortunately, it can be worked around using arithmetic operations. It also helps that it has the XOR operator, which means it suffices to identify letters vs. non-letters and apply XOR 32.

The code is kinda obfuscated by the use of "stack height" which saves 1 over pushing the first digit literally (_ push 0 and then append a digit). Unobfuscated, the code does the following:

Big loop:
  ,::    getchar(x), dup twice [x x x]
         exit (turn left) on EOF(-1), continue (turn right) otherwise(positive)
  _64/*  [x x2]  make chars 63 or below into 0 -> x2
  _32%   [x x3]  modulo 32 -> x3 (letter iff 1 <= x3 <= 26)
  (_26/  [x x4]  decrement and divide by 26 -> x4 (letter iff x4 == 0)
  )_2%   [x b]   increment and modulo 2 -> b (0 or 1, 1 means letter)
  _32*$  [x']    x XOR 32 if letter, x otherwise
  .      []      putchar
\$\endgroup\$
2
\$\begingroup\$

Scala 3, 52 bytes 43 bytes

_.map(c=>if(c>'Z')c.toUpper else c.toLower)

Attempt This Online!

-5 bytes thanks to @movatica

-4 bytes thanks to @Bubbler

\$\endgroup\$
2
  • 1
    \$\begingroup\$ 47 bytes using parenthesis instead of then \$\endgroup\$
    – movatica
    Mar 3 at 18:58
  • 1
    \$\begingroup\$ Change condition to c>'Z' to get 43 bytes. \$\endgroup\$
    – Bubbler
    Mar 12 at 5:14
2
\$\begingroup\$

R, 48 bytes

\(s)gsub("([A-Z]*)([a-z]*)","\\L\\1\\U\\2",s,,T)

(T for perl=TRUE)

\$\endgroup\$
1
\$\begingroup\$

Retina 0.8.2, 7 bytes

T`Ll`lL

Try it online! Link includes test cases. Explanation: Simply transliterates using the shortcuts for upper and lowercase letter ranges.

\$\endgroup\$
1
\$\begingroup\$

Charcoal, 10 bytes

⭆S⎇№αι↧ι↥ι

Try it online! Link is to verbose version of code. Explanation:

 S          Input string
⭆           Map over characters and join
    α       Predefined variable uppercase ASCII
   №        Contains
     ι      Current character
  ⎇         If true then
        ι    Current character
       ↧     Lowercased
          ι  Else current character
         ↥   Uppercased
             Implicitly print
\$\endgroup\$
1
\$\begingroup\$

Japt v2.0a0, 9 bytes

®c^H*Zè\l

Try it

®c^H*Zè\l­⁡​‎‎⁡⁠⁡‏‏​⁡⁠⁡‌⁢​‎‎⁡⁠⁢‏⁠‏​⁡⁠⁡‌⁣​‎‎⁡⁠⁣‏‏​⁡⁠⁡‌⁤​‎‎⁡⁠⁤‏‏​⁡⁠⁡‌⁢⁡​‎‎⁡⁠⁢⁡‏‏​⁡⁠⁡‌⁢⁢​‎‎⁡⁠⁢⁢‏⁠‎⁡⁠⁢⁣‏‏​⁡⁠⁡‌⁢⁣​‎‎⁡⁠⁢⁤‏⁠‎⁡⁠⁣⁡‏‏​⁡⁠⁡‌­
®          # ‎⁡Map each character Z to:
 c         # ‎⁢  It transformed by passing its charcode through:
  ^        # ‎⁣    XOR with
   H       # ‎⁤      32
    *      # ‎⁢⁡      Multiplied by
     Zè    # ‎⁢⁢      Number of matches of the following regex in Z:
       \l  # ‎⁢⁣        [A-Za-z] (alphabetical)
💎

Explanation created with the help of Luminespire.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.