DEV Community

loading...
The DEV Team

Daily Challenge #34 - WeIrD StRiNg CaSe

dev.to staff
The hardworking team behind dev.to ❤️
・1 min read

The goal of this challenge is to write a function that accepts a string and returns the same string with all even indexed characters uppercased and all odd indexed characters lowercased.

This indexing should be zero-based with the index in position zero being considered even. The input string will consist of only alphabetical characters and spaces. Spaces should only be present when there are multiple words.

Example:
to_weird_case('String'); # => returns 'StRiNg'
to_weird_case('Weird string case') # => returns 'WeIrD StRiNg CaSe'

Happy coding~!


This challenge comes from user xDranik. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge for a future post? Email yo+challenge@dev.to with your suggestions!

Discussion (31)

Collapse
ynndvn profile image
La blatte

Here goes a simple oneliner:

toWeirdCase=(s)=>[...s].map((e,i)=>i%2?e.toLowerCase():e.toUpperCase()).join('');

And the result:

toWeirdCase('String'); // "StRiNg"
toWeirdCase('Weird string case'); // "WeIrD StRiNg cAsE"
Collapse
dance2die profile image
Sung M. Kim

I believe case should be printed as CaSe as first letter (index 0) should be always capitalized.

Collapse
ynndvn profile image
La blatte

Indeed! Didn't catch that! Here is a little fix for that:

toWeirdCase=(a)=>a.split` `.map(s=>[...s].map((e,i)=>i%2?e.toLowerCase():e.toUpperCase()).join``).join` `;

which output is:

toWeirdCase('String'); // "StRiNg"
toWeirdCase('Weird string case'); // "WeIrD StRiNg CaSe"
Collapse
kenbellows profile image
Ken Bellows

Index 0 refers to the first letter of the entire string; we don't need to consider each word separately, just the string as a whole

Thread Thread
dance2die profile image
Sung M. Kim

Sorry about that.
I meant it as index 0 of each word.

the example shows the result should be

to_weird_case('Weird string case') # => returns 'WeIrD StRiNg CaSe'
Thread Thread
kenbellows profile image
Ken Bellows • Edited

Ah, you're right, that's interesting. I hadn't noticed that discrepancy with the capital 'C' in 'CaSe'; that makes this a more interesting challenge!

The original post should probably call that out a little more clearly, because it raises additional questions: Should punctuation count as a word separator? e.g., should 'word-other' become 'WoRd-oThEr' or 'WoRd-OtHeR'? Or should we only worry about letters and spaces? What characters are we considering?

@thepracticaldev , any help here?

Thread Thread
dance2die profile image
Sung M. Kim

For some reason, CodeWars isn't loading for me so won't be able to check the edge cases... 🤔

Collapse
inrsaurabh profile image
Saurabh Ranjan

In Js ( Many Optimised solutions are already given, just tried different way)

const to_weird_case = (string) => {
    let  newString = [];
    for( let i in string ) {
        if(i%2 == 0){
            newString.push(string[i].toUpperCase());
        } else {
            newString.push(string[i].toLowerCase());
        }
    }
    return newString.join('');
};

to_weird_case('Weird string case');
Collapse
andy profile image
Andy Zhao (he/him)

Ruby, not optimal 🙃

def to_weird_case(string)
  if string.include? " "
    string.split(" ").map { |word| word.split("") }.each do |letter_array|
      letter_array.each_with_index do|letter, index|
        letter.upcase! if index % 2 == 0 }}.map(&:join).join(" ")
      end
    end
  else
    string.split("").each_with_index do |letter, index|
      letter.upcase! if index % 2 == 0
    end.join
  end
end
Collapse
kenbellows profile image
Ken Bellows • Edited

Python solution:

toWeirdCase = lambda s: ''.join([c.lower() if i%2 else c.upper() for i,c in enumerate(s)])

print(toWeirdCase('String')) #=> StRiNg
print(toWeirdCase('Weird string case')) #=> WeIrD StRiNg cAsE

EDIT
@dance2die pointed out in this comment that the multi-word example in the post seems to suggest that each word should be considered and cased separately, rather than the whole string. In that case, this becomes a bit more interesting.

Here's a simple modification to account only for spaces separating words:

toWeirdCase = lambda s: ' '.join([wordToWeirdCase(w) for w in s.split(' ')])
wordToWeirdCase = lambda s: ''.join([c.lower() if i%2 else c.upper() for i,c in enumerate(s)])

print(toWeirdCase('String')) #=> StRiNg
print(toWeirdCase('Weird string case')) #=> WeIrD StRiNg CaSe

But this could get a lot more complex if we need to account for things like punctuation and other whitespace characters.

As one last example, here's one that handles alternative whitespace characters using regular expressions:

import re

toWeirdCase = lambda s: (
  s[:re.search(r'\S', s).start() if re.match(r'\s', s) else 0] +   # handle leading whitespace
  ''.join(
    [wordToWeirdCase(w) for w in re.findall(r'\S+(?:\s+)?', s)]
  )
)

wordToWeirdCase = lambda s: ''.join([c.lower() if i%2 else c.upper() for i,c in enumerate(s)])

print(toWeirdCase('String')) #=> 'StRiNg'
print(toWeirdCase('Weird string case')) #=> 'WeIrD StRiNg CaSe'
print(toWeirdCase('  hELLO world\tHOW\'S EVeryTHInG???')) #=> '  HeLlO WoRlD   HoW'S EvErYtHiNg???'
Collapse
alvaromontoro profile image
Alvaro Montoro • Edited

JavaScript

function formatText(message) {
    return message.split(" ")
                  .map(function(el) {
                    return el.split('')
                             .map(function(letter, idx) {
                               return idx % 2 === 0 ? letter.toLowerCase() : letter.toUpperCase();
                             })
                             .join('');
                  })
                  .join(' ')
  }

And as an extension, I used that function to create a Sponge Bob Mocking meme generator! (which is the first thing that I thought when I saw the challenge)

Collapse
itsasine profile image
ItsASine (Kayla)

At work, we just call this serial killer case :P

Collapse
laurentiumolnar profile image
LaurentiuMolnar

A simple solution in Javascript:

function toWeirdCase(string) {
  return string.split(' ')
    .map(word => {
      return word.split('')
        .map((char, index) => {
          if (index % 2 === 0) return char.toUpperCase()
          return char
        })
        .join('')
    })
    .join(' ')
}

console.log(toWeirdCase('string'))
console.log(toWeirdCase('Weird string  case'))
Enter fullscreen mode Exit fullscreen mode
Collapse
brightone profile image
Oleksii Filonenko

Elixir:

defmodule Case do
  require Integer

  def weird(string) do
    string
    |> String.graphemes()
    |> Enum.with_index()
    |> Enum.map(fn
      {char, i} when Integer.is_even(i) -> String.upcase(char)
      {char, _} -> String.downcase(char)
    end)
    |> Enum.join()
  end
end
Collapse
peter279k profile image
peter279k

Here is the simple solution with PHP:

function toWeirdCase($string) {
    $strings = explode(' ', $string);

    $stringsIndex = 0;
    foreach ($strings as $string) {
      $index = 0;
      for (; $index < strlen($string); $index++) {
        if ($index % 2 === 0) {
          $string[$index] = strtoupper($string[$index]);
        } else {
          $string[$index] = strtolower($string[$index]);
        }
      }

      $strings[$stringsIndex] = $string;
      $stringsIndex++;
    }

    return implode(' ', $strings);
}
Collapse
kerrishotts profile image
Kerri Shotts

Here's mine -- I'll admit that it took a little to recognize that the index was supposed to be word-based, not for the entire string. But that's what test cases are for! :-)

const TRANSFORMER = {
    LOWER: String.prototype.toLowerCase,
    UPPER: String.prototype.toUpperCase
};

const transform = (v, which) => which.apply(v);

const weirdCase = str => 
 str.split(" ")
    .map((part) => Array.from(part)
                        .map((ch, idx) => transform(ch, idx & 1 ? TRANSFORMER.LOWER 
                                                                : TRANSFORMER.UPPER ))
                        .join(""))
    .join(" ");

Gist: gist.github.com/kerrishotts/e3a213...

Collapse
tanguyandreani profile image
Tanguy Andreani • Edited

Ruby solution. Doesn’t use modulo.

Works with the strange edge case. Also sorry typed on tablet.

str = "Weird ,string case."

class << str
  def to_weird_case
    String.new.tap do |s|
      i = 0

      while i < self.length
        # work out with edge case
        if self[i] =~ /[^a-zA-Z]/
          s << self[i]
          i += 1
          next
        end

        # we add to_s because we may be out of bounds;
        # that way we get the empty string instead of nil
        # and an exception
        s << self[i].to_s.upcase
        s << self[i + 1].to_s.downcase
        i += 2
      end
    end
  end
end

str.to_weird_case
Collapse
hanachin profile image
Seiei Miyagi
def to_weird_case(s) s.split(' ').map { @1.chars.map.with_index
 { @2.even? ? @1.upcase : @1.downcase }.join }.join(' ') end
Collapse
andy profile image
Andy Zhao (he/him)

Ah I tried map_with_index but that's not a method. Did not know there was a .map.with_index!

Collapse
hanachin profile image
Seiei Miyagi

I'm glad to hear that. Enumerable has so many methods, which is useful but I take a little bit time to remember them.

Collapse
room_js profile image
JavaScript Room

Solution in Dart. Simple and not the shortest one, I guess. But it works =)

toWeirdCase(String str) {
  var result = new List();

  for (int i = 0; i < str.length; i++) {
    result.add(i%2 == 0 ? str[i].toUpperCase() : str[i].toLowerCase());
  }
  return result.join();
}

Link to the playground: dartpad.dartlang.org/f01143ca792ed...

Collapse
itsdarrylnorris profile image
Darryl Norris

PHP 💻

<?php

/**
 * Daily Challenge #34 - WeIrD StRiNg CaSe
 * @param  string $string
 * @return string
 */
function toWeirdCase(string $string): string
{
  return implode(" ",array_map(function($word) {
    $splitWord = str_split($word);
    return implode("", array_map(function($value, $key) {
      return ($key % 2 === 0) ? strtoupper($value) : strtolower($value);
    }, $splitWord, array_keys($splitWord)));

  }, explode(" ", $string)));
}


echo toWeirdCase('Weird string case');
// Output: WeIrD StRiNg CaSe

Collapse
sebvaldez profile image
Sebastian

Heres my ruby example

def to_weird_case (str)
  raise "Incorrect input, expected String" if str.class != String
  str.split(/\s/).map{|w| w.chars.each_with_index.map{|c,i| i%2==0 ? c.upcase : c }.join }.join(' ')
end

result

to_weird_case('string') => "StRiNg"
to_weird_case('Weird string case') => "WeIrD StRiNg CaSe"
Collapse
devparkk profile image
Dev Prakash • Edited
def weird_string (string) :
    result = ""
    for index in range(len(string)) :
        if index % 2 == 0 :
            result += string[index].upper()
        else :
            result += string[index].lower()
    return result

print (weird_string("Weird string case"))

Python one liner


def weird_string (string) :
    result = ("").join([string[i].lower() if i%2 else string[i].upper() for i in range(len(string))])
    return result

print(weird_string("Weird string case"))

Collapse
craigmc08 profile image
Craig McIlwrath

Haskell:

import Data.Char (toLower, toUpper)
import Control.Applicative

toWeirdCase :: String -> String
toWeirdCase = unwords . map weirdifier . words
              where weirdifier = getZipList
                               . (ZipList [if even i then toUpper else toLower | i <- [0..]] <*>)
                               . ZipList

I used applicative functors here mostly for fun. I think it looks nicer to define weirdifier as

weirdifier = zipWith (\i -> if even i then toUpper else toLower) [0..]
Collapse
kvharish profile image
K.V.Harish • Edited

My solution in js

const toWeirdCase = (str = '') => (str.split(' ').map((s) => ([...s].map((char, index) => (index % 2) ? char.toLowerCase() : char.toUpperCase())).join(''))).join(' ');
Collapse
dance2die profile image
Sung M. Kim

I've implemented based off of La blatte's answer.

const caser = {
  0: c => c.toUpperCase(),
  1: c => c.toLowerCase()   
}
const mod = i => i % 2
const weirdCase = text => text.split(' ').map(word => 
    [...word].map((c, i) => caser[mod(i)](c)).join('')
).join(' ')

console.log(["String", "Weird string case"].map(weirdCase))

prints,

["StRiNg", "WeIrD StRiNg CaSe"]
Collapse
carmenhchung profile image
Carmen Chung

Hey! We loved this challenge and actually got three developers to live code a solution in 15 minutes (with commentary): youtu.be/Z1fQ7J5fZhY

We also release similar videos every week on other Javascript, HTML/CSS, Python and Ruby challenges, so don't forget to like and subscribe if you're interested! ♥️

Collapse
hectorpascual profile image
Héctor Pascual

Python with a function :

def to_weird_case(string):
    weird_string = ''
    i = 0
    for c in string.lower():
        if i%2:
            weird_string += c
        else:
            weird_string += c.upper()
        i += 1
    return weird_string

One liner with list comprehension :

weird_case = ''.join([string[i].lower() if i%2 else string[i].capitalize() for i in range(0,len(string))])

Collapse
dbalseiro profile image
Diego Balseiro

Here is a little Haskell one-liner

import Data.Char (toUpper, toLower)

toWeirdCase :: String -> String
toWeirdCase = unwords . map (zipWith ($) (cycle [toUpper, toLower])) . words
Collapse
shaber profile image
ShaBer • Edited

A JS single line solution that works with multi-line texts:

toWeirdCase=s=>s.replace(/[A-z][^]?/g,m=>m[0].toUpperCase()+(m[1]||'').toLowerCase());
Enter fullscreen mode Exit fullscreen mode