26
\$\begingroup\$

Some of your employees have broken capslock keys and you're too cheap to replace them. Help them out by creating the shortest program possible to correct their work! Simply convert each character in a given string from uppercase to lowercase and vice-versa... but there's a twist!

You're also very excited for Christmas! So you're going to leave in a tiny "bug" that doesn't correct letters which are within sequences of Christmas (case-insensitive).

Input

For input you will use one single string (or array of bytes) that may contain newlines and ascii between 0x20 and 0x7e ( - ~). You don't need to worry about carriage returns or any other characters being in the string.

Output

The output should contain only the provided string with the upper and lowercase characters swapped (and the Christmas bug of course!). It can contain up to one extra trailing whitespace.

Christmas Bug

Let's explain this with an example:

Input: i CAN HARDLY WORK LIKE THIS please GET ME A NEW KEYBOARD FOR cHRISTMAS
Output: I Can HaRdly work lIke thiS PLEASE geT Me A new keyboard for ChriStmas

can contains "c" which is the first letter of Christmas, so that isn't changed. The next letter in Christmas is "h", which is in hardly (which also contains the "r"), so that isn't changed, etc. Christmas itself only has one letter unchanged because by the time the code reaches there, it's actually looking for "s", not "c".

Once the sequence is found, it should start all over again at "c", and begin iterating through Christmas once more. So ChristmasChristmas would be left unchanged.

Test Cases

Input: Hello World!
Output: hELLO wORLD!

Input: I like pie :)
Output: i LIKE PIE :)

Input: hELP my KeYboarD
       iS BROKEN
Output: Help MY kEyBOARd
        Is broken

Input: cHRISTMAS IS COMING REALLY SOON!
Output: cHRISTMAS is Coming really soon!

Input: C is the first letter in cHRISTMAS
Output: C IS ThE FIrST LETTER iN ChriSTMAS

Winner

This is so the shortest answer wins!

\$\endgroup\$
10
  • 6
    \$\begingroup\$ That 'no built ins which solve most the challenge' is a pretty strange restriction. And is 'swap case' really going to cause that many issues when half the challenge is identifying which letters aren't in 'christmas'? \$\endgroup\$
    – ATaco
    Commented Dec 19, 2016 at 22:25
  • 1
    \$\begingroup\$ Related: I am passive aggressive and want to insult my boss without him finding out \$\endgroup\$
    – Dennis
    Commented Dec 19, 2016 at 22:26
  • \$\begingroup\$ @ATaco, I added it last-minute because of feedback on the sandbox, I agree though so I've removed it. \$\endgroup\$ Commented Dec 19, 2016 at 22:28
  • \$\begingroup\$ Also, Test case 3, you swapped the first h, when that's in Christmas. \$\endgroup\$
    – ATaco
    Commented Dec 19, 2016 at 22:29
  • \$\begingroup\$ @ATaco, it looks for Christmas sequencially, so "h" is ignored until it finds "c", then it looks for "h", then "r", etc. \$\endgroup\$ Commented Dec 19, 2016 at 22:30

16 Answers 16

10
\$\begingroup\$

05AB1E, 16 bytes

Thanks to Emigna for saving a byte and fixing a bug!

vyÐl'ŒÎ¾èQi¼ëš}?

Explanation:

vy                # For each character in the string...
  Ð               #   Triplicate that character
   l              #   Convert to lowercase
    'ŒÎ           #   Compressed version of "christmas"
       ¾          #   Push the counting variable (let's call this N)
        è         #   Get the nth character of "christmas", with modular indexing
         Qi   }   #   If equal...
           ¼      #      N += 1
            ë     #   Else...
             š    #      Swapcase
               ?  #   Print that character

Uses the CP-1252 encoding. Try it online!

\$\endgroup\$
10
  • 1
    \$\begingroup\$ Does this work with newlines? \$\endgroup\$ Commented Dec 19, 2016 at 23:45
  • \$\begingroup\$ @redstarcoder Oops, it didn't. It's fixed now. \$\endgroup\$
    – Adnan
    Commented Dec 19, 2016 at 23:49
  • 2
    \$\begingroup\$ This looks just like tinsel. :D \$\endgroup\$
    – Titus
    Commented Dec 19, 2016 at 23:55
  • 1
    \$\begingroup\$ The output isn't correct (try for example Christmas as input), but if you remove u it should work. \$\endgroup\$
    – Emigna
    Commented Dec 20, 2016 at 13:20
  • 1
    \$\begingroup\$ @Izzy 05ab1e has existed for a long, long time. \$\endgroup\$
    – Pavel
    Commented Dec 21, 2016 at 1:24
5
\$\begingroup\$

V, 38, 36 bytes

ÄVumaOchristmasòÉf2x`a@"maj~HòHdjV~

Try it online! (contains input and expected output for comparison)

When I first saw this, I thought it would be extremely easy. In fact, if it were not for the "christmas" bug, this would just be 2 bytes: V~. The christmas bug makes it significantly harder, for a very hacky answer.

As usual, here is a hexdump:

00000000: c456 756d 614f 6368 7269 7374 6d61 731b  .VumaOchristmas.
00000010: f2c9 6632 7860 6140 226d 616a 7e48 f248  ..f2x`a@"maj~H.H
00000020: 646a 567e                                djV~
\$\endgroup\$
2
  • \$\begingroup\$ I would love to know more about V. \$\endgroup\$
    – ckjbgames
    Commented Feb 10, 2017 at 21:41
  • \$\begingroup\$ @ckjbgames Cool, I'd be happy to answer any questions you have! You can always ping me in the vim-golf room. Right now I'm working on making V a little bit easier to learn/creating a tutorial. \$\endgroup\$
    – DJMcMayhem
    Commented Feb 10, 2017 at 21:48
4
\$\begingroup\$

PHP, 113 110 102 bytes

while($o=ord($c=$argv[1][$i++]))echo chr(32|$o==ord(christmas[$k%9])?$o|0&$k++:ctype_alpha($c)*32^$o);

takes input from first command line argument. Run with -r.

breakdown

while($o=ord($c=$argv[1][$i++]))// loop through string characters
    echo chr(
        32|$o==ord(christmas[$k%9]) // if $c equals next character in "christmas"
            ?$o|0&$k++              // no change, increase "christmas" index
            :ctype_alpha($c)        // else if $c is a letter
                    *32^$o          // toggle bit 5 of the ascii code
        );
\$\endgroup\$
3
\$\begingroup\$

JavaScript, 122 118 114 107 104 93 bytes

f=
s=>s.replace(/./g,c=>(k=c.toLowerCase())=='christmas'[i%9]?++i&&c:k!=c?k:c.toUpperCase(),i=0)


F=s=>console.log(f(s))
F(`Hello World!`)
F(`I like pie :)`)
F(`hELP my KeYboarD
       iS BROKEN`)
F(`cHRISTMAS IS COMING REALLY SOON!`)
F(`C is the first letter in cHRISTMAS`)

  • 11 bytes off thanks @Neil.
\$\endgroup\$
1
  • \$\begingroup\$ Can't you use k!=c?k:c.toUpperCase() to save you a few bytes? \$\endgroup\$
    – Neil
    Commented Dec 31, 2016 at 14:47
2
\$\begingroup\$

MATL, 36 30 bytes

"@tk'schristma'H)=?HQXHx}Yo]&h

Strings with newlines need to be defined by concatenating with the ASCII code 10 (see example in the link with the test cases).

Try it online! Or verify all test cases.

Explanation

"              % Implicit input of a string. For each character in that string
  @            %   Push current character
  tk           %   Duplicate and convert to lowercase
  'schristma'  %   Push string. This is 'Christmas' in lowercase and circularly
               %   shifted such that the 'c' is in the second position
  H            %   Push contents of clipboard H, which is initiallized to 2.
               %   This value will be gradually increased when a new character
               %   from the the sequence is found
  )            %   Get character from 'schristma' at that (modular) position
  =            %   Are they equal?
  ?            %   If so
    HQ         %     Push contents of clipboard H and add 1
    XHx        %     Copy into clipboard K and delete
  }            %   Else
    Yo         %     Change case
  ]            %   End
  &h           %   Concatenate stack contents horizontally. This gives a string 
               %   with all characters processed up to now
               % Implicit end. Implicit display
          
\$\endgroup\$
2
\$\begingroup\$

Pyke, 31 25 bytes

FD.dґ~o@Dl3+{DIoK)R!Il3

Try it here!

\$\endgroup\$
2
  • \$\begingroup\$ Does this work with newlines? \$\endgroup\$ Commented Dec 20, 2016 at 20:50
  • \$\begingroup\$ @redstarcoder if you escape them as \n and surround the input in " then yes \$\endgroup\$
    – Blue
    Commented Dec 20, 2016 at 21:01
2
\$\begingroup\$

Perl 6, 84 bytes

{my $i=0;[~] (.lc~~"christmas".comb[$i%9]??(++$i&&$_)!!.ord>90??.uc!!.lc for .comb)}
\$\endgroup\$
2
\$\begingroup\$

C# 197 bytes

Not going to win with this, but hopefully the smallest C# implementation that works...

string C(string s){int i=0,j=0;var r="";for(;i<s.Length;){char c=s[i++],o=(char)32;if(c=="christmas"[j]|c=="CHRISTMAS"[j])j=j>7?0:j+1;else if(c>64&c<91)c+=o;else if(c>96&c<123)c-=o;r+=c;}return r;}

Explanation:

string C(string s)
{
    // define our two index ints
    // i for indexing across the input string
    // j for indexing across christmas
    int i = 0, j = 0;

    // r is our return string
    var r = "";

    // declare our loop
    // skip the initialisation and afterthought
    for (; i < s.Length;)
    {
        // get our current character c, and increment index i
        // initial our offset char o (difference between upper and lower case)
        char c = s[i++], o = (char)32;

        // check if c is the current character in our christmas bug
        if (c == "christmas"[j] | c == "CHRISTMAS"[j])
            // increment j (or reset to 0)
            j = j > 7 ? 0 : j + 1;

        // else if c is an upper case char
        else if (c > 64 & c < 91)
            // add our offset to make it lower case
            c += o;

        // else if c is lower case
        else if (c > 96 & c < 123)
            // subtract our offset to make it upper case
            c -= o;

        // append c to our return string r
        r += c;
    }

    return r;
}
\$\endgroup\$
2
\$\begingroup\$

Vyxal, 14 bytes

‛ß₌£Nƛ⇩¥h=[N&Ǔ

Try it Online! Outputs as a char list, s flag formats into string.

   £           # Store into the register
‛ß₌            # compressed string "christmas"
    N          # Swap case of each letter
     ƛ         # Over each letter
          [    # If
      ⇩        # The letter, lowercased
         =     # equals
       ¥h      # The first char of the register
           N   # Switch the case again
            &Ǔ # And shift the first char of the register to the end
\$\endgroup\$
1
\$\begingroup\$

Perl 6, 80 bytes

{my$i=0;S:g{.?<!{'christmas'.comb[$i%9]eq$/.lc&&++$i}>}=$/eq$/.lc??$/.uc!!$/.lc}

Try it

{   # bare block lambda with implicit parameter 「$_」

  my $i = 0;             # counter

  S                      # substitute and return ( implicitly against 「$_」 )
  :global
  {
    .                    # any char
    ?                    # work around a bug where 「$/」 doesn't get set

    <!{                  # fail this match if this block returns True
      'christmas'.comb\  # a list of the characters of 「christmas」
      [ $i % 9 ]         # grab a char from the list
      eq                 # is it equal to
      $/.lc              # the lowercase version of the char
      &&                 # if so
      ++$i               # increment 「$i」 ( result is True )
    }>

  }

  =                      # for each matched char

  $/ eq $/.lc            # is it lowercase?
  ?? $/.uc               # the uppercase it
  !! $/.lc               # otherwise lowercase it
}
\$\endgroup\$
3
  • \$\begingroup\$ I don't believe omitting the space in my $i=0; is legal. And I wouldn't be surprised if there were more whitespace-related syntax errors. \$\endgroup\$
    – bb94
    Commented Dec 20, 2016 at 20:45
  • 1
    \$\begingroup\$ @bb94 I literally included a link in to a site that will run the code. If you don't believe that will run, why don't you try it. I mean I wrote $/ eq $/.lc rather than $/.lc eq $/ so that I could remove the space before eq. \$\endgroup\$ Commented Dec 20, 2016 at 23:34
  • \$\begingroup\$ @bb94 I can confirm it working on the linked compiler. \$\endgroup\$ Commented Dec 20, 2016 at 23:58
1
\$\begingroup\$

Java 7, 200 bytes

String c(char[]a){String r="";int i=0,s;Character l='a';for(char c:a)if((s="christma".indexOf(l=l.toLowerCase(c)))==i|i>7&s==4){r+=c;i=i>7?0:i+1;}else r+=l.isUpperCase(c)?l:l.toUpperCase(c);return r;}

Ugly, but it works.. Can definitely without any doubt be golfed more.. I'm rusty..

Ungolfed:

String c(char[] a){
  String r = "";
  int i = 0,
      s;
  Character l = 'a';
  for(char c : a){
    if((s = "christma".indexOf(l = l.toLowerCase(c))) == i) | i > 7 & s == 4){
      r += c;
      i = i > 7
           ? 0
           : i+1;
    } else{
      r += l.isUpperCase(c)
       ? l
       : l.toUpperCase(c);
    }
  }
  return r;
}

Test code:

Try it here.

class M{
  static String c(char[]a){String r="";int i=0,s;Character l='a';for(char c:a)if((s="christma".indexOf(l=l.toLowerCase(c)))==i|i>7&s==4){r+=c;i=i>7?0:i+1;}else r+=l.isUpperCase(c)?l:l.toUpperCase(c);return r;}

  public static void main(String[] a){
    System.out.println(c("i CAN HARDLY WORK LIKE THIS please GET ME A NEW KEYBOARD FOR cHRISTMAS".toCharArray()));
    System.out.println(c("Hello World!".toCharArray()));
    System.out.println(c("I like pie :)".toCharArray()));
    System.out.println(c("hELP my KeYboarD\niS BROKEN".toCharArray()));
    System.out.println(c("cHRISTMAS IS COMING REALLY SOON!".toCharArray()));
    System.out.println(c("C is the first letter in cHRISTMAS".toCharArray()));
  }
}

Output:

I Can HaRdly work lIke thiS PLEASE geT Me A new keyboard for ChriStmas
hELLO wORLD!
i LIKE PIE :)
Help MY kEyBOARd
Is broken
cHRISTMAS is Coming really soon!
C IS ThE FIrST LETTER iN ChriSTMAS
\$\endgroup\$
1
  • 2
    \$\begingroup\$ Java 's beating Haskell and C#! \$\endgroup\$
    – Pavel
    Commented Dec 21, 2016 at 1:25
1
\$\begingroup\$

Python 100 bytes

def a(s,i=0,g=''):
 for c in s:a=c.lower()=='christmas'[i%9];i+=a;g+=[c.swapcase(),c][a]
 return g
\$\endgroup\$
1
\$\begingroup\$

Ruby, 63+1 = 64 bytes

Uses the -p flag.

i=0;gsub(/./){|c|c=~/#{"christmas"[i%9]}/i?(i+=1;c):c.swapcase}
\$\endgroup\$
1
\$\begingroup\$

Perl 5 -p, 62 57 bytes

@a=christmas=~/./g;s|\pL|lc$&eq$a[$i%9]&&++$i?$&:$&^$"|ge

Try it online!

\$\endgroup\$
0
\$\begingroup\$

C# 239 chars

var s=Console.ReadLine().ToCharArray();int j=0,i=0;var c="christmas";for(;j<s.Length;j++)if(s[j]==c[i%9]|s[j]==(c[i%9]-32))i++;else if(s[j]>64&s[j]<91)s[j]=(char)(s[j]+32);else if(s[j]>96&s[j]<123)s[j]=(char)(s[j]-32);Console.WriteLine(s);

more explicit version:

var s = Console.ReadLine().ToCharArray();
int j = 0,i = 0;
var c = "christmas";
for (var j = 0; j < s.Length; j++)
   if (s[j] == c[i%9]|s[j] == (c[i%9] - 32))// non case sensitive compare with c 
      i++;//next char in christmas
   else
      if (s[j] > 64 & s[j] < 91)//if between A and Z
         s[j] = (char)(s[j] + 32);//convert to a-z
      else
         if (s[j] > 96 & s[j] < 123)//if between a and z
            s[j] = (char)(s[j] - 32);//convert to A-Z
Console.WriteLine(s);

this is a pretty naïve solution, and probably can be improved (maybe we can allow implicit conversion to char?).

it assumes to be inside a function, reads from the console (stdin), and writes to it (stdout).

edit: Char.IsUpper(s[j]) is 2 bytes longer than s[j]>64&&s[j]<91, Char.ToUpper is longer than my version too.

\$\endgroup\$
0
\$\begingroup\$

Haskell, 222 207 Bytes

import Data.Char
s=(+(-65)).ord
f=(`divMod`32).s
l=[['a'..'z'],['A'..'Z']]
c=cycle$map s"CHRISTMAS"
k _[]=[]
k(a:b)(x:y)|isAlpha x=let(d,m)=f x in if(m==a)then(x:k b y)else(l!!d!!m:k(a:b)y)|1>0=x:k(a:b)y
main=interact$k c

updated:

import Data.Char
s=(+(-65)).ord
k _[]=[]
k(a:b)(x:y)|isAlpha x=let(d,m)=s x`divMod`32 in if(m==a)then(x:k b y)else([['a'..'z'],['A'..'Z']]!!d!!m:k(a:b)y)|1>0=x:k(a:b)y
main=interact$k$cycle$map s"CHRISTMAS"

How it works:

s=(+(-65)).ord

s x = ASCII value of x - ASCII value of 'A'

f=(`divMod`32).s

f (s x) = (0,s x) for uppercase, (1, (s x-32)) for lowercase

l=[['a'..'z'],['A'..'Z']]

parallel list of letters, indexable by f (lowercase->1->uppercase, uppercase->0->lowercase)

c = cycle $ map s "CHRISTMAS"

infinite list of the ascii values of uppercase christmas repeated

k _ []=[]

base case

k (a:b) (x:y) | isAlpha x = let (d,m) =f x
                             in if m == a
                                then x : k b y
                                else (l!!d)!!m : k (a:b) y
              | 1 > 0 = x : k (a:b) y

return non-alphanumeric characters, and either keep the letter if its s-value is the same as the current letter of christmas (going to the next letter), otherwise convert it to the other case and proceed

main=interact$k c

IO

\$\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.