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");

migrated from stackoverflow.com Aug 12 '17 at 21:06

This question came from our site for professional and enthusiast programmers.

  • What would be the output of titleCase("I'm a little tea pot");? – Yagna Patel Aug 12 '17 at 19:13
  • 3
    You mean it doesn't work when you move the var newString = stored.join(' '); above the loop? Well obviously that's because the array isn't yet filled. – Bergi Aug 12 '17 at 19:13

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(' ');
  • 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... – Benas Lengvinas Aug 12 '17 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.

  • 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). – 200_success Sep 9 '17 at 7:31

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"));

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 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.

  • Use [a-z] instead of \w. \w = [a-zA-Z0-9_]. – Tushar May 8 at 3:28

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.