2
var name = "AlbERt EINstEiN";

function nameChanger(oldName) {
var finalName = oldName;
// Your code goes here!
finalName = oldName.toLowerCase();

finalName = finalName.replace(finalName.charAt(0), finalName.charAt(0).toUpperCase());

for(i = 0; i < finalName.length; i++) {
    if (finalName.charAt(i) === " ")
        finalName.replace(finalName.charAt(i+1), finalName.charAt(i+1).toUpperCase());
}


// Don't delete this line!
return finalName;
};

// Did your code work? The line below will tell you!
console.log(nameChanger(name));

My code as is, returns 'Albert einstein'. I'm wondering where I've gone wrong? If I add in

console.log(finalName.charAt(i+1));

AFTER the if statement, and comment out the rest, it prints 'e', so it recognizes charAt(i+1) like it should... I just cannot get it to capitalize that first letter of the 2nd word.

Nate Barbettini
  • 51,256
  • 26
  • 134
  • 147
JoshTheGray
  • 117
  • 13

5 Answers5

4

There are two problems with your code sample. I'll go through them one-by-one.

Strings are immutable

This doesn't work the way you think it does:

finalName.replace(finalName.charAt(i+1), finalName.charAt(i+1).toUpperCase());

You need to change it to:

finalName = finalName.replace(finalName.charAt(i+1), finalName.charAt(i+1).toUpperCase());

In JavaScript, strings are immutable. This means that once a string is created, it can't be changed. That might sound strange since in your code, it seems like you are changing the string finalName throughout the loop with methods like replace().

But in reality, you aren't actually changing it! The replace() function takes an input string, does the replacement, and produces a new output string, since it isn't actually allowed to change the input string (immutability). So, tl;dr, if you don't capture the output of replace() by assigning it to a variable, the replaced string is lost.

Incidentally, it's okay to assign it back to the original variable name, which is why you can do finalName = finalName.replace(...).


Replace is greedy

The other problem you'll run into is when you use replace(), you'll be replacing all of the matching characters in the string, not just the ones at the position you are examining. This is because replace() is greedy - if you tell it to replace 'e' with 'E', it'll replace all of them!

What you need to do, essentially, is:

  1. Find a space character (you've already done this)
  2. Grab all of the string up to and including the space; this "side" of the string is good.
  3. Convert the very next letter to uppercase, but only that letter.
  4. Grab the rest of the string, past the letter you converted.
  5. Put all three pieces together (beginning of string, capitalized letter, end of string).

The slice() method will do what you want:

if (finalName.charAt(i) === " ") {
    // Get ONLY the letter after the space
    var startLetter = finalName.slice(i+1, i+2);
    // Concatenate the string up to the letter + the letter uppercased + the rest of the string
    finalName = finalName.slice(0, i+1) + startLetter.toUpperCase() + finalName.slice(i+2);
}

Another option is regular expression (regex), which the other answers mentioned. This is probably a better option, since it's a lot cleaner. But, if you're learning programming for the first time, it's easier to understand this manual string work by writing the raw loops. Later you can mess with the efficient way to do it.

Working jsfiddle: http://jsfiddle.net/9dLw1Lfx/

Further reading:

Community
  • 1
  • 1
Nate Barbettini
  • 51,256
  • 26
  • 134
  • 147
  • 1
    ... Because? You should at least explain why this change is necessary, especially since this question seems like homework. – xdumaine Aug 18 '15 at 00:06
  • I tried this, and it returns 'AlbErt einstein'. Not really sure why it's grabbing the first 'e', and not the one after the space? – JoshTheGray Aug 18 '15 at 00:06
  • @xdumaine I agree, I was in the middle of expanding the explanation when you commented :) – Nate Barbettini Aug 18 '15 at 00:07
  • See OP's comment on this answer. The line will replace the first character matching the character at that index. I.e if `finalName.charAt(i+1)` is an `e` then it will replace the first `e` in the string, not necessarily the one at index `i+1` – xdumaine Aug 18 '15 at 00:10
  • 1
    Good immutability explanation! – xdumaine Aug 18 '15 at 00:16
  • Worked like that. Thank you for taking the time to answer my question. I was beginning to question my future as a dev, seeing as I couldn't get some stupid letters to capitalize lol. Thank you again! – JoshTheGray Aug 18 '15 at 00:20
  • @xdumaine Thanks! Appreciate the feedback and catching my errors. Cheers! – Nate Barbettini Aug 18 '15 at 00:23
  • 1
    @MartDellon Absolutely! Happy to help. I could tell you were looking for a basic explanation. We've all struggled with this stuff at one time or another. Keep learning man! – Nate Barbettini Aug 18 '15 at 00:26
4

You can simplify this down a lot if you pass a RegExp /pattern/flags and a function into str.replace instead of using substrings

function nameChanger(oldName) {
    var lowerCase = oldName.toLowerCase(),
        titleCase = lowerCase.replace(/\b./g, function ($0) {return $0.toUpperCase()});
    return titleCase;
};

In this example I've applied the change to any character . after a word boundary \b, but you may want the more specific /(^| )./g

Paul S.
  • 64,864
  • 9
  • 122
  • 138
  • This is pretty cryptic, especially to a beginner. – xdumaine Aug 18 '15 at 00:11
  • @xdumaine Which part specifically? I tried to make it clearer by splitting it into three lines. I've edited in some references – Paul S. Aug 18 '15 at 00:13
  • i doubt OP would recognize this replace syntax means that it's using regular expressions, let alone how you came up with those regex or what they mean. That's fairly advanced for a "your code goes here" string manipulation problem. – xdumaine Aug 18 '15 at 00:14
1

Another good answer to this question is to use RegEx to do this for you.

var re = /(\b[a-z](?!\s))/g;
var s = "fort collins, croton-on-hudson, harper's ferry, coeur d'alene, o'fallon"; 
s = s.replace(re, function(x){return x.toUpperCase();});
console.log(s); // "Fort Collins, Croton-On-Hudson, Harper's Ferry, Coeur D'Alene, O'Fallon"

The regular expression being used may need to be changed up slightly, but this should give you an idea of what you can do with regular expressions

Capitalize Letters with JavaScript

Community
  • 1
  • 1
mwilson
  • 12,295
  • 7
  • 55
  • 95
1

The problem is twofold:

1) You need to return a value for finalName.replace, as the method returns an element but doesn't alter the one on which it's predicated.

2) You're not iterating through the string values, so you're only changing the first word. Don't you want to change every word so it's in lower case capitalized?

This code would serve you better:

   var name = "AlbERt EINstEiN";

function nameChanger(oldName) {

    // Your code goes here!

    var finalName = [];
    oldName.toLowerCase().split(" ").forEach(function(word) {
        newWord = word.replace(word.charAt(0), word.charAt(0).toUpperCase());
        finalName.push(newWord);
    });


    // Don't delete this line!
    return finalName.join(" ");
};

    // Did your code work? The line below will tell you!
    console.log(nameChanger(name));
Laurent
  • 1,554
  • 19
  • 42
-4
if (finalName.charAt(i) === " ")

Shouldn't it be

if (finalName.charAt(i) == " ")

Doesn't === check if the object types are equal which should not be since one it a char and the other a string.

duellsy
  • 8,497
  • 2
  • 36
  • 60
  • Are you sure that charAt(i) returns a string and not a char? – Nate Barbettini Aug 18 '15 at 00:05
  • This is **not** answering the question in any way. *And* it's wrong, as there's no `char` type in JavaScript, `charAt` just returns a string of length 1. – Darkhogg Aug 18 '15 at 00:06
  • CharAt should be a char while " " should be a string. But since it's javascript, don't remember if ' ' == " " due to weak typing. – Justin Chou Aug 18 '15 at 00:06
  • 1
    @JustinChou _JavaScript_ doesn't have a _Char_ type, it uses _String_ with length `1` (or maybe `2` in some edge cases with an unusual USC-16 character, not sure would need to read spec) – Paul S. Aug 18 '15 at 00:10