I am trying to capitalize the first letter of every word in the string. I wanted to do it in 3 steps:
Turn string into an array using .split().
Create a loop and change the first letter in every word by addressing it with an array index.
Finally I wanted to use .join to put everything back in a string.
But something went wrong and I can't go to the 3rd step. The for loop does change the letter to uppercase, but when I return the variable cap it only returns the first capitalized letter of the last word in the string. In the example it's P(the last word is pot), if I erase pot it returns T(because tea becomes the last word).
Why doesn't the cap variable return the whole array with capitalized first letters? What am I missing?
Here's the code:
function titleCase(str) {
var arr = str.split(" ");
for (i = 0; i < arr.length; i++) {
var cap = arr[i][0].toUpperCase();
}
return cap;
}
titleCase("I'm a little tea pot");
That's because you're just returning the cap variable which will contain the last words first letter to upper case (left by last iteration).
function titleCase(str) {
var arr = str.split(" ");
for (i = 0; i < arr.length; i++) {
var word = arr[i];
// capitalized first letter + rest of the word
var capitalizedWord = word[0].toUpperCase() + word.slice(1);
arr[i] = capitalizedWord; // replace the uncapitalized word with capitalized one
}
return arr.join(" "); // join with spaces to make it a sentence again
}
titleCase("I'm a little tea pot");
It's because cap is only a variable so as you loop through your words it keeps getting overwritten by the first letter of the next word. Make it an array or concatenate the next letter onto it.
I think this is the answer:
const capitalizeFirst = data => data.replace(/[\w']+/g, x => x[0].toUpperCase() + x.slice(1).toLowerCase())
console.log(capitalizeFirst("I'm a little tea pot"))
You are overriding the variable cap in each iteration.
Your code slightly modified:
function titleCase(str) {
var arr = str.split(" ");
var cap = "";
for (i = 0; i < arr.length; i++) {
if (i != arr.length - 1) {
cap += arr[i][0].toUpperCase() + arr[i].substr(1) + " ";
} else {
cap += arr[i][0].toUpperCase() + arr[i].substr(1);
}
}
return cap;
}
titleCase("I'm a little tea pot");
You are committing a cardinal sin of Javascript! Don't ever declare variables inside of a loop.
function titleCase(str) {
var cap;
var arr = str.split(" ");
for (i = 0; i < arr.length; i++) {
cap = arr[i][0].toUpperCase();
}
return cap;
}
Would be the proper way to type what you have written.
When your for loop iterates in your example, it re-declares the variable each time which causes some bad things to happen. In my example, it is re-defined each time but only declared once.
However, this is all still incorrect for your problem. This will only give you the single letter when you want the entire string. Try something like this
function titleCase(str) {
var arr = str.split(" ");
var wordToCap;
var capWord;
var capArray = [];
for (var i = 0; i < arr.length; i++) {
wordToCap = arr[i];
capWord = wordToCap.charAt(0).toUpperCase() + wordToCap.substring(1);
capArray.push(capWord);
}
return capArray.join(" ");
}
There are much more elegant ways of solving this problem, but hopefully all the steps broken down here will help you understand what your loop is doing and should be doing.
Good luck!
ES2015 solution:
const titleCase = str =>
str.split(' ').map(word =>
word.charAt(0).toUpperCase() + word.slice(1)
).join(' ');
titleCase("I'm a little tea pot"));
Working example: https://jsfiddle.net/ecdkxrjd/
Related
I am trying to find the first pair of repeated words in the string, but I can only get it to find all repeated pairs in order of which word is first in the sentence, not by the first pair. For example in string "I love my anthony so much with all my hearts love" the output should be my, but it gives me love.
let Sentence = 'I love my anthony so much with all my hearts love';
function wordRepeat(str) {
let splitStr = str.split(' ');
let list = [];
for (let i = 0; i < splitStr.length; i++) {
for (let j = i + 1; j < splitStr.length; j++) {
if (splitStr[i].match(splitStr[j])) {
//repeat = splitStr[i];
list.push(splitStr[i]);
}
}
}
//console.log(list);
return list[0];
}
console.log(wordRepeat(Sentence));
The output should be 'my', BUT I get 'love', however 'my' is the correct answer because it is the first pair.
You can use something like this:
function getDuplicate(inString){
const arr=inString.split(/\W+/g);// This is a Regular Expression - See it in use at https://regex101.com/r/X0Cyxx/1
return arr.find( (word,index) =>
arr.slice(0,index).includes(word)
);
}
EDIT:
I modified line 2 to include punctuation, as #Phil suggested. Thanks, #Phil!
The following function should uppercase the first letter of every word in a sentence (str)! Unfortunately it doesn't work and I cant find the solution!
function titleCase(str) {
let arr = str.toLowerCase().split(" ");
for (let i = 0; i < arr.length; i++) {
arr[i].charAt(0).toUpperCase();
}
return arr.join(" ");
}
console.log(titleCase("I'm a little tea pot"));
You need to assign the result of uppercasing the letter, and concatenate it to the rest of the word:
function titleCase(str) {
let arr = str.toLowerCase().split(" ");
for (let i = 0; i < arr.length; i++) {
arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].substring(1);
}
return arr.join(" ");
}
console.log(titleCase("I'm a little tea pot"));
It's also easier to use map:
function titleCase(str) {
return str.split(" ").map(s => s.charAt(0).toUpperCase() + s.substring(1)).join(" ");
}
console.log(titleCase("I'm a little tea pot"));
arr is an array of strings, but strings are immutable - simply calling toUpperCase() on a character will just give you a reference to a new, uppercase character, without changing the original string. You need to explicitly reassign the array item:
function titleCase(str) {
let arr = str.toLowerCase().split(" ");
for (let i = 0; i < arr.length; i++) {
arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].slice(1);
}
return arr.join(" ");
}
console.log(titleCase("I'm a little tea pot"));
Or, perhaps more elegantly, you could use a regular expression. The following uses lookbehind, which works in recent versions of Chrome, Opera, and Node; lookbehind makes for cleaner-looking code, but it's not supported everywhere:
const titleCase = str => str.replace(
/(?<=^|\s)\S/g,
firstChar => firstChar.toUpperCase()
);
console.log(titleCase("I'm a little tea pot"));
Or, without lookbehind:
const titleCase = str => str.replace(
/(\S)(\S*)/g,
(_, firstChar, rest) => firstChar.toUpperCase() + rest
);
console.log(titleCase("I'm a little tea pot"));
You can update your code this way
First lowercase all the characters
Loop through string indexes
If index is 0 or index - 1 is a space character make the str[index] to uppercase
Keep appending it a string and return at end
function titleCase(str) {
let LowerCaseStr = str.toLowerCase()
let final =''
for (let i = 0; i < LowerCaseStr.length; i++) {
if(i === 0 || LowerCaseStr[i-1] === ' '){
final += LowerCaseStr[i].toUpperCase()
} else{
final += LowerCaseStr[i]
}
}
return final
}
console.log(titleCase("I'm a little tea pot"));
I split the string at ’ ’ and store all the words in in strSplit. The used FORLOOP for capitalizing first letter of every word to capitalize and stored in variable firstLetter. Stored rest of the word in variable restLetter. Then use + to add firstLetter and restLetter and stored this result in newLetter. Now i want to use join to take away “” form each word so that it becomes a one string with every first letter capitalized in each word. but my if i applied join on newLetter it is not working.
function titleCase(str) {
var strSplit = (str.split(' '));
var newLetter = [];
var returnString;
var firstLetter;
var restLetter;
for(i=0; i <=(strSplit.length-1); i++){
firstLetter = strSplit[i].charAt(0).toUpperCase();
for(i=0; i <=(strSplit.length-1); i++){
firstLetter = strSplit[i].charAt(0).toUpperCase();
restLetter = strSplit[i].slice(1, str.Split);
newLetter = firstLetter + restLetter;
newLetter.join(" and ");
}
return newLetter;
}
}
titleCase("I'm a little tea pot");
You can easily do it like this:
function titleCase(str) {
return str.split(' ')
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
.join(' ')
}
console.log(titleCase("I'm a little tea pot"));
Here we split by space then we make each word start with uppercase by using map and then concatenating the first character to uppercase and the rest of the word lowercase, and then join the words array with space.
I found the solution myself with same approach i started!! Here it is:
function titleCase(str) {
var strSplit = (str.split(' '));
var newLetter = [];
var firstLetter;
var restLetter;
for(i=0; i <strSplit.length; i++){
firstLetter = strSplit[i].charAt(0).toUpperCase();
restLetter = strSplit[i].slice(1, str.Split).toLowerCase();
newLetter.push(firstLetter + restLetter);
}
return newLetter.join(" ");
}
titleCase("I'm a little tea pot");
I have this code :
//make first letter of each word capital
function titleCase(str) {
/*
* 1. change all letters to lower case
* 2. split words
* 3. set each 1st letter to Capital
* 4. combine array back into string
*/
arr = [];
str.toLowerCase();
arr = str.split(" ");
for (var index = 0; index < arr.length; index++) {
arr[index].charAt(0).toUpperCase();
}
str= arr.join(" ");
return str;
}
console.log(titleCase("Potato potato potato"));
And I don't understand why toLowerCase() and toUpperCase() are not working. What am I doing wrong ?
There are 2 updates required
Reassign str.toLowerCase() to str
Reassign updated array value back in array.
Please note, until and unless you reassign the values, the original value does not change. Hence, the result remained unaffected.
//make first letter of each word capital
function titleCase(str) {
/*
1. change all letters to lower case
2. split words
3. set each 1st letter to Capital
4. combine array back into string
*/
arr = [];
str = str.toLowerCase(); // **** Problem 1 - Reassigning
arr = str.split(" ");
for (var index = 0; index < arr.length; index++) {
// **** Problem 2 - Reassigning
arr[index] = arr[index].charAt(0).toUpperCase() + arr[index].slice(1);
}
str= arr.join(" ");
return str;
}
console.log(titleCase("Potato potato potato"));
You need to reassign (overwrite) the value inside the array after you change it. Otherwise, the array remains unchanged. Besides, you forgot to add the rest of the string (arr[index].slice(1)) to the uppercased letter.
function titleCase(str) {
let arr = [];
str.toLowerCase();
arr = str.split(" ");
for (var index = 0; index < arr.length; index++) {
arr[index] = arr[index].charAt(0).toUpperCase() + arr[index].slice(1); // <-- Changes
}
str= arr.join(" ");
return str;
}
console.log(titleCase("Potato potato potato"));
EDIT
Here is my own ES6 one-liner version :
titleCase = str => str.trim().split(" ").map( word => word.charAt(0).toUpperCase() + word.slice(1) ).join(" ")
console.log(titleCase("Potato potato potato"));
Explanation :
titleCase = str => str
.trim() // Removes extra spaces
.split(" ")
.map( word =>
word.charAt(0).toUpperCase() + word.slice(1) // Uppercases 1st letter, adds the rest of the word, returns the whole
)
.join(" ") // Reforms a string
you can simply do
function convert(str){
return str.split(' ').map(e => e.replace(/([A-Za-z])(\w+)/, (x, y, z) => y.toUpperCase()+z.toLowerCase())).join(' ');
}
console.log(convert('Potato potato pOtato'))
short solution:
var titleCase = (str)=>str.toLowerCase().split(' ').map(word=>word.charAt(0).toUpperCase()+word.slice(1)).join(' ');
calling:
titleCase('Potato potato potato');
Splitting the string by space and map a lambda to the resulting array. The lambda turns up the first letter and append the rest of the word.
as pointed out in the comments:
var titleCase = (str)=>str.toLowerCase().split(' ').reduce((currentString, word)=>currentString+(currentString ? ' ':'')+word.charAt(0).toUpperCase()+word.slice(1));
this works also and loops only one time.
Working on a CoderByte problem and the first for loop isn't executing on the first or last loop. The function is to convert every letter to the next one after it in the alphabet, then switch all vowels to uppercase. For example input "coderbyte" is returning "fpdfsczUE" when it should be "dpdfsczUf". All variables and tests seem to be functioning (see comments). Any help would be appreciated - they give the answers but won't explain why this won't work.
function LetterChanges(str) {
// convert every letter in a string to the letter after in the alphabet,
// then convert all vowels to uppercase, and return the string.
var alpha = "abcdefghijklmnopqrstuvwxyz";
var vowels = "aeiou";
for (var i=0; i<str.length; i++) {
// return (alpha.indexOf(str[i]) !== -1); checks true on first loop
if (alpha.indexOf(str[i]) !== -1) {
//return alpha[alpha.indexOf(str[i]) + 1]; // returns d correctly
// return alpha.indexOf(str[i]) + 1; // returns 3 correctly
//return str[i]; returns "c" correctly
// return str.replace(str[i], "X"); returns Xoderbyte correctly
// return str.replace(str[i+1], alpha[alpha.indexOf(str[i]) + 1]);
//returns cdderbyte correctly
// BUG: why isn't the line below working on the first and last
// loop ?
// ie. input "coderbyte" returns "fpdfsczUE"
str = str.replace(str[i], alpha[alpha.indexOf(str[i]) + 1]);
}
}
//return alpha[alpha.indexOf(str[i])];
for (var j=0; j<str.length; j++) {
if (vowels.indexOf(str[j]) !== -1) {
str = str.replace(str[j], str[j].toUpperCase());
}
}
return str;
}
Your question output is not proper
"coderbyte" needs to change to "dpEfsczUf" not "dpdfsczUf".
We need to replace character at particular index as str.replace will replace first occurrence only.
replaceAt function can help
So modified code below can work
String.prototype.replaceAt=function(index, character) {
return this.substr(0, index) + character + this.substr(index+character.length);
}
function LetterChanges(str) {
// convert every letter in a string to the letter after in the alphabet,
// then convert all vowels to uppercase, and return the string.
var alpha = "abcdefghijklmnopqrstuvwxyz";
var vowels = "aeiou";
for (var i=0; i<str.length; i++) {
if (alpha.indexOf(str[i]) !== -1) {
str = str.replaceAt(i, alpha[alpha.indexOf(str[i]) + 1]);
}
}
for (var j=0; j<str.length; j++) {
if (vowels.indexOf(str[j]) !== -1) {
str = str.replaceAt(j, str[j].toUpperCase());
}
}
return str;
}
You're misunderstanding how .replace() works. (see Satyajit's comment on your question) This is why the second part of your function works flawlessly; once a vowel has been converted to upper case, it can't be the basis of another character's transformation.
Regarding the first loop: if a letter in a pass after the first one matches a letter closest to i=0, then that letter will be the one that's replaced, not the one you intended.
If you use a debugger or even add a console.log(str) after the first loop's assignment, it will be evident what's going on.