I have this code which does the job, however it seems to me that the same could be done with less code. And why if I put 'var newString = stored.join(' ');' below 'var stored=[];' the code doesn't work?
function titleCase(str) {
var lower = str.toLowerCase();
var arr = lower.split(' ');
var stored = [];
//takes a string from arr
for(var i = 0; i<arr.length; i++) {
//splits and stores the string to letters
var word = arr[i].split(''); // ['l','i','t'...]
// takes the first letter from the array and makes it uppercase
for(var k=0; k<1; k++){
var upper = word[k].toUpperCase();
word.shift();
word.unshift(upper);
var joined = word.join('');
stored.push(joined);
}
}
var newString = stored.join(' ');
return newString;
}
titleCase("I'm a little tea pot");
6 Answers 6
You can use String#replace with a regexp:
function titleCase(str) {
return str.toLowerCase() // change the string to lowercase
.replace(/\S+/g, function(s) { // get all non space characters sequences
return s.charAt(0).toUpperCase() + s.substring(1); // uppercase the 1st letter and combine with the rest of the string
});
}
console.log(titleCase("I'm a little tea pot"));
You can split the string by space, then use map
function to iterate over words and uppercase each word and then join
it back again:
"I'm a little tea pot"
.split(' ')
.map(function(word) {
return word[0].toUpperCase() + word.substring(1);
})
.join(' ');
-
\$\begingroup\$ huh...so the argument 'word' in the function is the current value being procesed? And by 'word[0]' it takes the first letter of the word? I thought that you have to use '[ ]' only on an array. Or that value being processed becomes an array somehow? Sorry for dumb questions... \$\endgroup\$Benas Lengvinas– Benas Lengvinas2017年08月12日 20:50:21 +00:00Commented Aug 12, 2017 at 20:50
A more succinct string replace variant:
str.replace (/(^|\s)\S/g, match => match.toUpperCase () );
The regexp matches the satrt of string or a space followed by a non-space character. The entrire match is up-cased and returned.
-
\$\begingroup\$ Consider using
\b
instead of(^|\s)
. Not only is it simpler, it also has the advantage of working with words that follow punctuation (such as a double-quote). \$\endgroup\$200_success– 200_success2017年09月09日 07:31:13 +00:00Commented Sep 9, 2017 at 7:31
Instead of providing a complete solution like the other answers (migrated from SO), I'll point out a few specific things that could be improved:
//splits and stores the string to letters var word = arr[i].split(''); // ['l','i','t'...]
That's not really necessary. You can used indexed access, a length
property and the same iteration on the string itself.
// takes the first letter from the array and makes it uppercase for(var k=0; k<1; k++){ var upper = word[k].toUpperCase();
Why is this a loop? It loops exactly once, testing whether 0 < 1
. Just drop that and place
var upper = word[0].toUpperCase();
word.shift(); word.unshift(upper);
Don't do that. It move the whole array around and then back. Just assign to the first index:
word[0] = upper;
var joined = word.join('');
If we didn't split the arr[i]
word in the word
array, we could instead use
var joined = arr[i][0].toUpperCase() // upper
+ arr[i].slice(1); // the rest of the string
var stored = []; //takes a string from arr for(var i = 0; i<arr.length; i++) { ... stored.push(joined); }
Instead of filling that stored
array, you could have mutated the original one (for a tiny bit of better performance). But creating a new array is fine.
However, when creating a new array with one item per item from the original array, the map
method helps a lot to remove the boilerplate loop, array instantiation and pushing.
var lower = str.toLowerCase(); var arr = lower.split(' '); ... var newString = stored.join(' '); return newString;
Since you specifically asked about doing it with less code: use less variables. If you only use a variable exactly once, the expression might as well be inlined:
var arr = str.toLowerCase().split(' ');
...
return stored.join(' ');
It's often beneficial for clarity to use more of such descriptive variable names, but it also is a lot longer.
If you apply all these points, you'll basically end up with madox2's solution.
I would use the regex /([^ ]+)/g
to match for each word and then change the first letter.
var titleCase = (text) => text.replace(/([^ ]+)/g, (w) => w[0].toUpperCase() + w.substring(1));
console.log(titleCase("I'm a little tea pot"));
I would change the regex to only match the first character in a word instead of using a concatenation like others did:
function titleCase(str) {
return str.replace(/(^|\s)\w/g, (s) => s.toUpperCase() );
}
console.log(titleCase("I'm a little tea pot"));
However there are some questions you might want to consider. For example a newspaper would not capitalize a (or an or the) and hyphenated words are (High-Quality) are sometimes capitalized.
-
\$\begingroup\$ Use
[a-z]
instead of\w
.\w
=[a-zA-Z0-9_]
. \$\endgroup\$Tushar– Tushar2018年05月08日 03:28:02 +00:00Commented May 8, 2018 at 3:28
titleCase("I'm a little tea pot");
? \$\endgroup\$var newString = stored.join(' ');
above the loop? Well obviously that's because the array isn't yet filled. \$\endgroup\$