loading...

Daily Challenge #190 - capitalizeFirstLast

thepracticaldev profile image dev.to staff ・1 min read

For this challenge, you will have to write a function called capitalizeFirstLast or capitalize_first_last. This function will capitalize the first and last letter of each word, and lowercase what is in between.

capitalizeFirstLast "and still i rise" -- "AnD StilL I RisE"

Rules:

  • The function will take a single parameter, which will be a string.
  • The string can contain words separated by a single space.
  • Words are made of letters from the ASCII range only.
  • The function should return a string.
  • Only the first and last letters are uppercased.
  • All the other letters should be lowercased.

Examples:

capitalizeFirstLast "and still i rise"               -- "AnD StilL I RisE"
capitalizeFirstLast "when words fail music speaks"   -- "WheN WordS FaiL MusiC SpeakS"
capitalizeFirstLast "WHAT WE THINK WE BECOME"        -- "WhaT WE ThinK WE BecomE"
capitalizeFirstLast "dIe wITh mEMORIEs nOt dREAMs"   -- "DiE WitH MemorieS NoT DreamS"
capitalizeFirstLast "hello"                          -- "HellO"

Good luck!


This challenge comes from aminnairi here on DEV. Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

Posted on by:

thepracticaldev profile

dev.to staff

@thepracticaldev

The hardworking team behind dev.to ❤️

Discussion

markdown guide
 

An easy option is to start off by lowercasing the whole thing...
(JS)

capitalizeFirstLast = s => s.toLowerCase().replace(/\b\w|\w\b/g, c => c.toUpperCase())

Regex matches single letters preceded by a word boundary or followed by a word boundary.

Running through the examples:

[
  "and still i rise",
  "when words fail music speaks",
  "WHAT WE THINK WE BECOME",
  "dIe wITh mEMORIEs nOt dREAMs",
  "hello"
].map(s => `"${s}" -> "${capitalizeFirstLast(s)}"`).join("\n")

>> 

"and still i rise" -> "AnD StilL I RisE"
"when words fail music speaks" -> "WheN WordS FaiL MusiC SpeakS"
"WHAT WE THINK WE BECOME" -> "WhaT WE ThinK WE BecomE"
"dIe wITh mEMORIEs nOt dREAMs" -> "DiE WitH MemorieS NoT DreamS"
"hello" -> "HellO"
 
 

Javascript + Regex "One" liner.

function capitalizeFirstLast(string) {
  return string.replace(/(\w)((\w*)(\w))?/g, (_, a, __, b, c) => [a.toUpperCase(), b && b.toLowerCase(), c && c.toUpperCase()].filter(Boolean).join(''))
}

Click here if you're curious what the regular expression does

 

First try in Ruby, I think this can be done without splitting and rejoining.

def capitalizeFirstLast(string)

    string.split(' ').each do |word|
        word.downcase!
        word.sub!(/\A./) {|match| match.upcase} # First Char
        word.sub!(/.\z/) {|match| match.upcase} # Last Char
    end.join(' ')

end

puts capitalizeFirstLast "tHIs is my string"
# => ThiS IS MY StrinG
 

The most straightforward way to fix this is probably to do something as:

export const capitalizeFirstLast = (inputString: string): string => 
    inputString
        .split(' ')
        .reduce((accumulator: string, entry: string) =>
            { 
                let fixedWord: string = capitalizeFirstLastInWord(entry);

                return `${accumulator} ${fixedWord}`;
            }, "");


const capitalizeFirstLastInWord = (word: string) =>
    word.charAt(0).toUpperCase()
    + word.slice(1, -1).toLowerCase()
    + word.charAt(entry.length -1).toUpperCase()

but probably there are better ways to do this :P

EDIT: Ofc some tuning is required if we also accept punctuation and, numbers or any other characters of sort, but the requirements state letters, so...

 

I think there are a couple mistakes in your solution.

In your capitalizeFirstLastInWord function, you are using the variable entry. I think you meant word?

And in your capitalizeFirstLast function, you are using an undefined variable fixedWord. Maybe this was the return value of your previous function call?

Other than that, I really like how you used the reduce method to solve this one!

 

You are 100% right, I did some last-minute refactoring and I was a bit distracted! :P

I will edit it for future readers :)

About the reduce part: The idea came because last year I was able to work with an
awesome team which enforced very good practices & a very cool "implementation"
of functional programming, I miss that team a lot!

 

C++

string capitalizeFirstLast(string s){
    string modifiedString = "";
    for(int i=0;i<s.length();i++){
        if(i==0 || (i>0 && s[i-1]==' ') || (i<s.length()-1 && s[i+1] == ' ') || i==s.length()-1){
           modifiedString += char(toupper(s[i]));
        }
        else{
            modifiedString += char(tolower(s[i]));
        }
    }
    return modifiedString;
}

Python one liner

def capitalizeFirstLast(s):
  return  " ".join([word[0].upper()+word[1:-1].lower()+(word[-1].upper() if len(word)>1 else "") for word in s.split()])
 

First & Fast & Last try with JS

capitalizeFirstLast = sentence => {
    var arrWords = sentence.toLocaleLowerCase().split(" ");
    var newArrWords = [];

    arrWords.forEach((x,i)=> {
        var wordLength = x.length;
        if(wordLength > 2){
            newArrWords.push(x.charAt(0).toUpperCase() + x.substr(1,wordLength-2) + x.charAt(wordLength - 1).toUpperCase());
        }
        else{
            newArrWords.push(x.toUpperCase());
        }
    });
return newArrWords.join(" ");
}
 

Cool, many ways of doing this.

This is what I came up with:

function capitalizeFirstLast(string = "") {
  const _firstLastWord = word => {
    if (!word || word.length <= 1) {
      return word.toUpperCase();
    }

    let len = word.length;
    const upperAt = i => word.charAt(i).toUpperCase();
    return `${upperAt(0)}${word.substr(1, len - 2)}${upperAt(len - 1)}`;
  };

  return string.length
    ? string
        .toLowerCase()
        .split(" ")
        .map(_firstLastWord)
        .join(" ")
    : string;
}
 

Python

var = input("Enter the String: ")

def capitalizeFirstLast(x):
        x = x.lower()
        x = list(x)
        x[0] = x[0].upper()
        x[len(x)-1] = x[len(x)-1].upper()

        for i in range(len(x)):
                if x[i] == ' ':
                        x[i-1] = x[i-1].upper()
                        x[i+1] = x[i+1].upper()

        return(''.join(x))

print(capitalizeFirstLast(var))
 

Something like this with JS

function capitalizeFirstLast(string) {
  var toLowerCase = string.toLowerCase();
  var splitString = toLowerCase.split(" ");

  var transformedStrings = [];

  splitString.forEach(word => {
    var upperCaseFirstLetter = word.charAt(0).toUpperCase();
    var upperCaseLastLetter = word.charAt(word.length - 1).toUpperCase();
    var getRestOfString = word.slice(1, word.length - 1);

    var mergeString = upperCaseFirstLetter + getRestOfString + upperCaseLastLetter;

    transformedStrings.push(mergeString);
  })

  var joinStrings = transformedStrings.join(" ");

  return joinStrings;
};
 

One letter words don't pass. Try and still i rise you will get AnD StilL II RisE

 

Came up with this Elm solution while I was procrastinating at work today:

capitalizeFirstLast : String -> String
capitalizeFirstLast input =
  let
    capitalizeFirst = String.left 1 >> String.toUpper
    capitalizeLast  = String.right 1 >> String.toUpper
    lowercaseMiddle = String.slice 1 -1 >> String.toLower
    transform word  =
      if String.length word < 2 then
        String.toUpper word
      else
        capitalizeFirst word ++ lowercaseMiddle word ++ capitalizeLast word
  in
  String.words input
    |> List.map transform
    |> String.join " "

Not overly different from the other solutions here, but neat nonetheless.

 
console.clear();
const capitalizeFirstLast = (str) => {
  let strArr = str.split(" ");
  let parseStr = strArr.map(item => {
        itemArr = [...item];
        midStr = itemArr.slice(1,itemArr.length-1).join('');
        return item.length > 1 ? item[0].toUpperCase() + midStr.toLowerCase() + item[item.length-1].toUpperCase() : item[0].toUpperCase();      
  }).join(' ');
  console.log(parseStr);  
}
capitalizeFirstLast('my name is NAVDEEP singh')

JSBin Link

 

Haskell

import Data.Char (toUpper, toLower)

capitalizeFirstLast :: String -> String
capitalizeFirstLast = unwords . map f . words
  where f (c:[]) = [toUpper c]
        f (c:cs) = toUpper c : map toLower (init cs) ++ [toUpper (last cs)]
 

Ugly, but it works (dart)

String capitalizeFirstLast(String words) {
  return words.split(" ").map((word) {
    word = word.toLowerCase();
    word = word[0].toUpperCase() + word.substring(1, word.length);
    if(word.length > 1) {
      word = word.substring(0, word.length-1) + word[word.length-1].toUpperCase();
    }
    return word;
  }).toList().join(" ");
}
 

Rust Solution:

fn capital_first_last(sentence: &str) -> String {
    sentence.split_whitespace()
        .map(|word| first_last(word))
        .collect::<Vec<String>>()
        .join(" ")
}

fn first_last(word: &str) -> String {
    let chars: Vec<char> = word.chars().collect();
    chars[0].to_uppercase().nth(0).unwrap().to_string() +
        &chars[1..chars.len()-1].into_iter().collect::<String>() + 
        &chars.last().unwrap().to_uppercase().nth(0).unwrap().to_string()
}
 

Another JS example

const capitalizeFirstAndLast = string => {
    const splitString = str => str.split(' ');
    const fixWords = array =>
        array.map(v =>
            v.length < 2
                ? v.toUpperCase()
                : `${v.charAt(0).toUpperCase()}${v.toLowerCase().substr(1, v.length - 2)}${v.charAt(v.length - 1).toUpperCase()}`
        );
    const joinString = array => array.join(' ');

    return string
        |> splitString
        |> fixWords
        |> joinString
};

//TESTING
const tests = [
    "and still i rise",
    "when words fail music speaks",
    "WHAT WE THINK WE BECOME",
    "hello",
];

console.log(tests.map(capitalizeFirstAndLast));
/*
[
  'AnD StilL I RisE',
  'WheN WordS FaiL MusiC SpeakS',
  'WhaT WE ThinK WE BecomE',
  'HellO'
]
*/
 

python

import re


def to_uc(match_group):
    return match_group.group(0).upper()


def capitalize_first_last(in_str):
    in_str = in_str.lower().strip()
    in_str = re.sub(r'\s+', ' ', in_str)
    in_str = re.sub(r'(^[a-z])', to_uc, in_str)
    in_str = re.sub(r'([a-z]$)', to_uc, in_str)
    in_str = re.sub(r'(\s[a-z])', to_uc, in_str)
    in_str = re.sub(r'([a-z]\s)', to_uc, in_str)

    print in_str


# -----
capitalize_first_last('and still i    rise')
capitalize_first_last('when words fail music speaks')
capitalize_first_last('WHAT WE THINK WE BECOME')
capitalize_first_last('dIe wITh mEMORIEs nOt dREAMs')
capitalize_first_last('hello')

# -----
# AnD StilL I RisE
# WheN WordS FaiL MusiC SpeakS
# WhaT WE ThinK WE BecomE
# DiE WitH MemorieS NoT DreamS
# HellO

 

JAVASCRIPT ANSWER

function capitalizeFirstLast(str) {
    return str.replace(/[^\s]+/g, (match) => {
        replaceStr = '';
        const len = match.length;

        for(i=0; i<len; i++){
            if(i === 0 || i === len-1){
                replaceStr = replaceStr + match[i].toUpperCase();
            } else {
                replaceStr = replaceStr + match[i].toLowerCase();
            }
        }

        return replaceStr
    });
};
 

Not the best-looking of all, but it works. C#, with a lot of fiddling with Join and Select.

public static string CapitalizeFirstLast(this string input) => String.Join(" ", input.Split(" ").Select(sub => new string(String.Join("", sub.ToLower().ToCharArray().Select((v, k) => (k == 0 || k == sub.Length - 1) ? Char.ToUpper(v) : Char.ToLower(v))))));

And, to test it.

string[] testStrings = {
    "and still i rise",
    "when words fail music speaks",
    "WHAT WE THINK WE BECOME",
    "dIe wITh mEMORIEs nOt dREAMs",
    "hello"
};

foreach(string s in testStrings) {
    Console.WriteLine(s.CapitalizeFirstLast());
}