why js .replace() work incorrectly in double letters?

I tried to write function that will return string in weird case. For Example:

toWeirdCase("String") //StRiNg

So, it seems to work, but not in all cases. When we put string with double letters function return something really weird (without doubles all is fine):

I don`t need other way to implementation, i need explain what is wrong in my function. Can somebody?

function toWeirdCase(string) {
  let arrSentence = string.toLowerCase().split(' ');
  arrSentence = arrSentence.map((word) => {
    for (let i = 0; i < word.length; i++) {
      if (i % 2 == false) {
        word = word.replace(word[i], word[i].toUpperCase())
      }
    }
    return word
  });
  arrSentence = arrSentence.join(' ');
  return arrSentence
}


console.log(toWeirdCase('Loooooks')) //LOOoooKs
console.log(toWeirdCase('Looks')) //LOokS

Answer

As Pointy and Jared Farrish mentioned, .replace, like any other function, doesn’t care about the expressions given as arguments, it only cares about the values they’re evaluated to. Consider the following code:

var word = 'Loooooks';

console.log(word[0]); // logs 'L'
console.log(word[1]); // logs 'o'
console.log(word[2]); // also logs 'o'
console.log(word[3]); // also logs 'o'

console.log(word[1], word[3]) // logs 'o', 'o'
console.log(word[1] === word[3]); // logs true, different expressions but with equal values

In the example shown, word[1] and word[3] are expressions, and their values are 'o' and 'o' respectively :D, since expressions are evaluated to their values, doing:

word = word.replace(word[3], word[3].toUpperCase());

is effectively the same as doing:

word = 'Loooooks'.replace('o', 'o'.toUpperCase());

which will obviously replace the first ‘o’ it encounters in the string, producing the output 'LOooooks' instead of 'LooOooks'.

Therefore, in order to replace the right characters, you either split the word into an array, then iterate over each character, replacing the “odd” ones (they’re tecnically even), and finally joining everything back together:

// spliting variable word into an array
var splitWord = word.split(''); // ['L', 'o', 'o', 'o', 'o', 'o', 'k', 's']

// iterating over each character, replacing the odd ones
for (let i = 0; i < splitWord.length; i++) {
    if (i % 2 === 0) {
        splitWord[i] = splitWord[i].toUpperCase();
    }
}

// joining everything back together
word = splitWord.join('');
console.log(word); // LoOoOoKs

Jared Farrish version is basically a more compact way to do the same thing.

Or you can also use a Regular Expression to match every pair of characters and then upper casing the first character of each pair:

// The regex /..?/g matches every pair of characters while
// ignoring the absence of a last character in words with an odd
// number of characters.
word.replace(/..?/g, match => match[0].toUpperCase() + (match[1] || ''));

And if you’re interested in really WeIrD CaSe a phrase or even some multi-line text with one single replace, instead of using /..?/g you could use /[A-z][^]?/g, to also match character pairs:

var text = 'this isnatfancy nr weird-casedntext!';
text = text.replace(/[A-z][^]?/g, match => match[0].toUpperCase() + (match[1] || ''));
console.log(text);

Leave a Reply

Your email address will not be published. Required fields are marked *