0

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
mplungjan
  • 169,008
  • 28
  • 173
  • 236
kleopa
  • 35
  • 3
  • 5
    The `.replace()` call doesn't care about the value of `i`; it's going to look for that particular letter and will operate on the first one found in the string. – Pointy Mar 10 '21 at 14:36
  • 3
    Side note: I strongly recommend **never** comparing a number to `true` or `false`. Don't use `i % 2 == false`. Instead, use `i % 2 === 0`. The rules for `==` with booleans are easily misunderstood and tricky to remember. For instance, although `Boolean(2)` is `true`, `2 == true` is `false`. – T.J. Crowder Mar 10 '21 at 14:37

3 Answers3

0

Imagine word = "butter" and i=2. Then this line:

word.replace(word[i], word[i].toUpperCase())

will replace all occurrences of t with T, resulting in word = "buTTer".

Mark Roberts
  • 138
  • 7
0

The approach is problematic, since regex doesn't generally replace by position. I would recommend reduce instead.

const oddify = (odd, letter, pos) => odd + (pos % 2 === 0 ? letter.toUpperCase() : letter)
const weird = text => text.split('').reduce(oddify, '')

console.log(weird('word'))
console.log(weird('something'))
Jared Farrish
  • 48,585
  • 17
  • 95
  • 104
0

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 is\na\tfancy \n\r weird-cased\ntext!';
text = text.replace(/[A-z][^]?/g, match => match[0].toUpperCase() + (match[1] || ''));
console.log(text);
Daniel
  • 46
  • 1
  • 3