Help With Title Case a Regex Sentence Problem

Tell us what’s happening:
I think I must be misunderstanding a concept here. I have split the sentence into an array made it lower case. I then iterate through each sting in the array using a for loop. At each iteration I capitalise the first letter of the string and assign it to a variable called newLetter. I then create a regular expression to locate the first character of the sting and use the replace method to replace it with the new letter. However after all this when I then console.log(newStr) it results in the same lower case array and the fist letters have not been replace?

Any help appreciated!

Your code so far


function titleCase(str) {
 var newStr = str.toLowerCase()
 console.log(newStr)
newStr = newStr.split(" ")
 console.log(newStr)

for (i = 0; i < newStr.length; i++){
var newLetter = newStr[i][0].toUpperCase()
console.log(newLetter)
var regex = /^./
newStr[i].replace(regex,newLetter)
console.log(newStr)
 
}
 return str;
}

titleCase("I'm a little tea pot");

Your browser information:

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36.

Challenge: Title Case a Sentence

Link to the challenge:
https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/title-case-a-sentence

some methods change the value on which they are called, some others don’t change it but return a new value

Strings are completely immutable, which means that any method on the string will always return new string

Still getting to grips with the concept of immutable in functioning code.

I have edited it and as far as I can tell in my editor it works correctly but it doesn’t pass any tests? Any guidance?

Looking at the solutions it seems I took a more literal system approach to the problem, can you suggest ways to follow the same method but streamline it?

function titleCase(str) {
  var lcStr = str.toLowerCase()
  console.log(lcStr)
  lcStr = lcStr.split(" ")
  console.log(lcStr)
  var newStr = ''
  for (i = 0; i < lcStr.length; i++){
    var ucLetter = lcStr[i][0].toUpperCase()
    console.log('This is cycle ' + i + ' ' + ucLetter)
    var regex = /^./
    newStr = newStr.concat(' ',lcStr[i].replace(regex,ucLetter))
    console.log(newStr) 
  }
  console.log(newStr);
  return newStr;
}
titleCase("I'm a little tea pot");

It seems you are adding a space at the beginning…
to confirm write console.log("-->" + newStr + "<--") instead of the one checking newStr now. Or whatever else. If there is a space between the symbol and the beginning or the end of the string you will know you are adding extra spaces

hint: strings are immutable, but arrays are not. You can change the elements of the array.

Ah good spot. So this was because I wanted to ad a space between the concat strings. To get around this I put in an if statment that will only insert a space after the first word. Now it all seems correct but still won’t pass. Any suggestion? I suppose instead of trying to concat strings I could edit each word in the array and use .join to just provide spaces between. could be simpler.

function titleCase(str) {
  var lcStr = str.toLowerCase()
  console.log(typeof(lcStr))
  console.log(lcStr)
  lcStr = lcStr.split(" ")
  console.log(typeof(lcStr))
  console.log(lcStr)
  var newStr = ''

for (i = 0; i < lcStr.length; i++){
 var ucLetter = lcStr[i][0].toUpperCase()
   console.log('This is cycle ' + i + ' ' + ucLetter)
 var regex = /^./
 
 if (i == 0) {
   newStr = newStr.concat('',lcStr[i].replace(regex,ucLetter))
   console.log(newStr)
 } else {
   newStr = newStr.concat(' ',lcStr[i].replace(regex,ucLetter))
   console.log(newStr)
 }
}
console.log(newStr)
  return newStr;
}

titleCase("sHoRt AnD sToUt");

I have also taken a look at this simple solution

function titleCase(str) {
  return str.toLowerCase().replace(/(^|\s)\S/g, L => L.toUpperCase());
}

I understand everything up until the L=> L.toUpperCase(). This is in the section that tells the replace method what to replace the regex with. Am I correct in saying that it is replacing it with the result of an anonymous function? If so, what indicates that L parameter represents the first letter as apposed to just replacing it?

I found the following on MDN but I still don’t quite understand.
You can specify a function as the second parameter. In this case, the function will be invoked after the match has been performed. The function’s result (return value) will be used as the replacement string. (Note: the above-mentioned special replacement patterns do not apply in this case.) Note that the function will be invoked multiple times for each full match to be replaced if the regular expression in the first parameter is global.

Okay so I did the array method with .join method. It seems a bit cleaner. However this still doesn’t pass the test?

function titleCase(str) {
  var lcStr = str.toLowerCase()
  console.log(typeof(lcStr))
  console.log(lcStr)
  lcStr = lcStr.split(" ")
  console.log(typeof(lcStr))
  console.log(lcStr)
  var newArr = []

  for (i = 0; i < lcStr.length; i++){
    var ucLetter = lcStr[i][0].toUpperCase()
   console.log('This is cycle ' + i + ' ' + ucLetter)
    var regex = /^./
    newArr.push(lcStr[i].replace(regex,ucLetter));
    console.log(newArr)
  }
    console.log(newArr)
    var newStr = newArr.join(' ')
    console.log(newStr)
    return newStr;
}
titleCase("sHoRt AnD sToUt");


instead of with just a pattern you can call the replace method with a function. In this case what’s inside the round parenthesis is not captured, the other part of the regex pattern outside of the round parenthesis is what is being replaced. in total it is “find the first non space character (\S) found at the beginning of the string (^) or after a space character (\s) and replace it with its upper case version”, as the regex has the g flag this is done for all the characters that match the pattern

for debugging I would need to be at my computer, I can’t right now

the documentation will tell you what is being passed in the callback function, and what the method does with the returned value. there is no special syntax that tell a function or method what to do, you will just have to find their behaviour reading about them

in this case what is passed in the callback function is what is being matched by the regex pattern, and the returned value is substituted to that

Thanks @ilenia that makes perfect sense. Further reading into MDN explains this.

You can specify a function as the second parameter. In this case, the function will be invoked after the match has been performed. The function’s result (return value) will be used as the replacement string. (Note: the above-mentioned special replacement patterns do not apply in this case.) Note that the function will be invoked multiple times for each full match to be replaced if the regular expression in the first parameter is global.

The arguments to the function are as follows:

Possible name Supplied value
match The matched substring.
p1, p2, ... The n th string found by a parenthesized capture group, provided the first argument to replace() was a RegExp object. (Corresponds to $1 , $2 , etc. above.) For example, if /(\a+)(\b+)/ , was given, p1 is the match for \a+ , and p2 for \b+ .
offset The offset of the matched substring within the whole string being examined. (For example, if the whole string was 'abcd' , and the matched substring was 'bc' , then this argument will be 1.)
string The whole string being examined.

The only think I’m still unsure of is why my updated solution wont pass the tests…

what tests are you not passing?
all of them or just a few? in this case, of those you are not passing, what should you return, what are you returning?

if all of them, try opening browser console and then run tests, are there any errors? Can you think how to solve them?

@ilenia I opened up the browser console and saw a reference error for i being not defined in the for loop. It passed the test by adding var i = 0 instead of i = 0. I understand the error and corrected it but I’m unsure why it sprung. In the past I have never had any issues by not defining i in a for loop. Is it because I reference i within in the loop?