Problem
Write a function that accepts a string, capitalizes the first letter of each word in the string, and returns the capitalized string.
Examples
function('a short sentence') => 'A Short Sentence'
function('a lazy fox') => 'A Lazy Fox'
function('look, it is working!') => 'Look, It Is Working!'
Code
I've solved the above problem using a few methods. If you'd like to review the codes and provide any change/improvement recommendations please do so, and I'd really appreciate that.
Python
def capitalize_built_in_title(sentence: str) -> str:
"""Capitalizes the first letters and preserves the spaces"""
return sentence.title()
def capitalize_naive_one(sentence: str) -> str:
"""Capitalizes the first letters and doesn't preserve the spaces"""
words = sentence.split()
for index_word, word in enumerate(words):
word_list = split_char_by_char_list(word)
for index_letter, letter in enumerate(word_list):
if index_letter == 0:
word_list[index_letter] = letter.upper()
word = "".join(word_list)
break
words[index_word] = word
return " ".join(words)
def capitalize_naive_two(sentence: str) -> str:
"""Capitalizes the first letters and doesn't preserve the spaces"""
words = sentence.split()
for index_word, word in enumerate(words):
words[index_word] = word[:1].upper() + word[1:]
return " ".join(words)
def capitalize_naive_three(sentence: str) -> str:
"""Capitalizes the first letters and preserves the spaces"""
import regex as re
split_on_first_letter = list(
re.splititer(r'(?i)(?<=^|\s)([a-z])', sentence))
for index, item in enumerate(split_on_first_letter):
if item is not None and len(item) == 1:
split_on_first_letter[index] = item.upper()
return "".join(split_on_first_letter)
def split_char_by_char_re(string: str):
import re
return re.findall(r'.', string)
def split_char_by_char_regex(string: str):
import regex as re
return re.findall(r'.', string)
def split_char_by_char_list(string: str):
return list(string)
if __name__ == '__main__':
# ---------------------------- TEST ---------------------------
DIVIDER_DASH_LINE = '-' * 50
GREEN_APPLE = '\U0001F34F'
RED_APPLE = '\U0001F34E'
test_sentences = ['hey there, how was your day?',
' good day! ', ' it waS GreaT!']
capitalized_sentences = [
'Hey There, How Was Your Day?', ' Good Day! ', ' It WaS GreaT!']
# ---------------------- DONT REPEAT YOURSELF -------------------------------
for index, sentence in enumerate(test_sentences):
print(DIVIDER_DASH_LINE)
if capitalized_sentences[index] == capitalize_built_in_title(sentence):
print(f'{GREEN_APPLE} "{sentence}" => "{capitalize_built_in_title(sentence)}"')
else:
print(f'{RED_APPLE} "{sentence}" => "{capitalize_built_in_title(sentence)}"')
if capitalized_sentences[index] == capitalize_naive_one(sentence):
print(f'{GREEN_APPLE} "{sentence}" => "{capitalize_naive_one(sentence)}"')
else:
print(f'{RED_APPLE} "{sentence}" => "{capitalize_naive_one(sentence)}"')
if capitalized_sentences[index] == capitalize_naive_two(sentence):
print(f'{GREEN_APPLE} "{sentence}" => "{capitalize_naive_two(sentence)}"')
else:
print(f'{RED_APPLE} "{sentence}" => "{capitalize_naive_two(sentence)}"')
if capitalized_sentences[index] == capitalize_naive_three(sentence):
print(f'{GREEN_APPLE} "{sentence}" => "{capitalize_naive_three(sentence)}"')
else:
print(f'{RED_APPLE} "{sentence}" => "{capitalize_naive_three(sentence)}"')
Output
--------------------------------------------------
π "hey there, how was your day?" => "Hey There, How Was Your Day?"
π "hey there, how was your day?" => "Hey There, How Was Your Day?"
π "hey there, how was your day?" => "Hey There, How Was Your Day?"
π "hey there, how was your day?" => "Hey There, How Was Your Day?"
--------------------------------------------------
π " good day! " => " Good Day! "
π " good day! " => "Good Day!"
π " good day! " => "Good Day!"
π " good day! " => " Good Day! "
--------------------------------------------------
π " it waS GreaT!" => " It Was Great!"
π " it waS GreaT!" => "It WaS GreaT!"
π " it waS GreaT!" => "It WaS GreaT!"
π " it waS GreaT!" => " It WaS GreaT!"
JavaScript
// --- Problem
// Write a function that accepts a string. The function should
// capitalize the first letter of each word in the string then
// return the capitalized string.
// --- Examples
// function('a short sentence') => 'A Short Sentence'
// function('a lazy fox') => 'A Lazy Fox'
// function('look, it is working!') => 'Look, It Is Working!'
function capitalize_naive_one(sentence) {
words = [];
for (let word of sentence.split(' ')) {
if (word != '') {
word = (word[0].toUpperCase() + word.slice(1));
}
words.push(word);
}
return words.join(' ');
}
function capitalize_naive_two(sentence) {
capitalized_sentence = sentence[0].toUpperCase();
for (let i = 1; i < sentence.length; i++) {
if (sentence[i - 1] === ' ') {
capitalized_sentence += sentence[i].toUpperCase();
} else {
capitalized_sentence += sentence[i];
}
}
return capitalized_sentence;
}
test_sentences = ['hey there, how was your day?', ' good day! ', ' it waS GreaT!'];
capitalized_sentences = ['Hey There, How Was Your Day?', ' Good Day! ', ' It WaS GreaT!'];
count = 0;
for (let sentence of test_sentences) {
if (capitalized_sentences[count] === capitalize_naive_one(sentence) && capitalized_sentences[count] === capitalize_naive_two(sentence)) {
console.log('π "'.concat(sentence, '" => "', capitalized_sentences[count], '"'));
}
count++;
}
-
1\$\begingroup\$ You are not just capitalizing the first letter of each word, you have different variations where the same phrase gives both "red" and "green" output. Just "capitalizing the first letter of each word" is relatively simple. \$\endgroup\$RomanPerekhrest– RomanPerekhrest2019εΉ΄10ζ17ζ₯ 16:41:35 +00:00Commented Oct 17, 2019 at 16:41
-
1\$\begingroup\$ I can cover all your "green" cases with single function (with retaining all spaces and without redundant lowercasing). If that suits your requirement? \$\endgroup\$RomanPerekhrest– RomanPerekhrest2019εΉ΄10ζ17ζ₯ 17:03:59 +00:00Commented Oct 17, 2019 at 17:03
1 Answer 1
JavaScript
- Javascript uses
camelCase
by convention notsnake_case
- Undeclared variables are placed in global scope or throw a parsing error in strict mode. The further a variable's scope is from the current scope the longer it takes to get the reference and thus the slower the code. You have not declared
words
,capitalized_sentence
and more in the testing code - Best to use constants for variables that do not change.
- Always use strict equality
===
and inequality!==
as they are faster and unless you are familiar with JS type coercion safer to use as they do not coerce type.
Rewrite
Rewriting your function using idiomatic JS
function capitalize(str) {
const words = [];
for (const word of str.split(" ")) {
if (word !== '') { word = word[0].toUpperCase() + word.slice(1) }
words.push(word);
}
return words.join(" ");
}
You could also do a one liner using string replace and a RegExp
const capitalize = str => str.replace(/\b[a-z]/g, char => char.toUpperCase());
However the regular expression does make it a little slow.
Immutable strings
JavaScript string are immutable, and thus you must take great care when handling strings as allocation overheads can slow things down. Avoid needless copying of strings
Accessing characters
The quickest way to get at characters in a string is via String.charCodeAt(idx)
For simple capitalization if you know that the char is lower case String.fromCharCode(str.charCodeAt(0) - 32)
is twice as fast as str[0].toUpperCase()
With the above two points in mind you can double (or better as it skips already uppercase words) the performance with the following.
- Only copies words if they need capitalization.
- Uses the character code to do the capitalization.
- Uses the one array, to avoid overhead building a second array.
.
function capit(str) {
const words = str.split(" ");
var i = 0, char;
for (const word of words) {
word !== "" && (char = word.charCodeAt(0)) > 96 && char < 122 &&
(words[i] = String.fromCharCode(char - 32) + word.slice(1));
i++;
}
return words.join(" ");
}
Explore related questions
See similar questions with these tags.