'String.replace() is replacing at the wrong index even though the index is passed correctly

Here is the prompt for what I need to do. I still haven't figured out the full solution yet, and I know this is not optimal at all (I'm a complete beginner and just trying to get something working for now), but that's not what my question is.

/* There are two types of potions:

Growing potion: "A"

Shrinking potion: "B"

If "A" immediately follows a digit, add 1 to the digit using your "addOne" function

If "B" immediately follows a digit, subtract 1 from the digit using your subtractOne function

Create a function "usePotions" that returns a string according to these rules, removing the potions once they've been consumed.

Example:

usePotions("3A7851") ➞ "47851"

usePotions("9999B") ➞ "9998"

usePotions("9A123") ➞ "10123"

usePotions("567") ➞ "567"

*/

I am using the string.replace() method in order to both increment or decrement the digit before A or B, and remove the A or B. For the strings with "A" in them, the code is working perfectly fine. For the one with B, even though the correct index is being passed into the replace method (which is 3), it's replacing the digit at index 0. I can't for the life of me figure out why the same exact code is behaving differently. I tried manually passing different indexes and it keeps replacing the character at index 0.

const addOne = (num) => num + 1;
const subtractOne = (num) => num - 1;

const usePotions = (str) => {
  let newStrA;
  let finalStrA;
  let newStrB;
  let finalStrB;
  if (!str.includes("A") && !str.includes("B")) return str;
  if (str.includes("A")){
    newStrA = str.replace(str[str.indexOf("A")-1], addOne(Number(str[str.indexOf("A")-1])))
    finalStrA = newStrA.replace("A", "");
    return finalStrA;
  }
  if (str.includes("B")){
    console.log(str.indexOf("B")-1);
    newStrB = str.replace(str[str.indexOf("B")-1], subtractOne(Number(str[str.indexOf("B")-1])))
    finalStrB = newStrB.replace("B", "");
    return finalStrB;
  }
}

console.log(usePotions("3A7851"));
console.log(usePotions("9999B"));
console.log(usePotions("9A123"));
console.log(usePotions("567"));


Solution 1:[1]

You may have misunderstood what string.replace() does, and how it can solve your problem. It will replace a string (which can be a character or more) into another one, so, as soon as there is an occurence it will replace it.

That's what you are doing right now, you are replacing the character 9 (from str[str.indexOf("B")-1]) into itself minus 1, and you don't specify where you want it to be replaced, so javascript will just take the first coming 9 coming and replace it. That's why you got 8999 and not 9998.

You can solve this by using string.substr() and doing the following:


    minusOne = subtractOne(Number(str[str.indexOf("B")-1])).toString()
    newStrB = str.substr(0, str.indexOf("B")-1) + minusOne + str.substr(index + minusOne.length)

Solution 2:[2]

You could take an object for the two functions for incrementing or devrementing a value. This approach allows to usethe letter for selecting the wanted function and return a new value for replacing the letter and leading digits.

For replacement use a regular expression which groups the numerical value and the letter with an alternative of A or B. In the replacement function omit the first parameter (the match of the complete regeular expression), here denoted with an underscore, which has just a symbolic meaning of being unused. The rest of the parameters get the content of each group.

function usePotions(string) {
    const fn = {
        A: v => +v + 1,
        B: v => v - 1
    };
    return string.replace(/(\d+)(A|B)/g, (_, d, letter) => fn[letter](d));
}

console.log(usePotions("3A7851"));
console.log(usePotions("9999B"));
console.log(usePotions("9A123"));
console.log(usePotions("567"));
console.log(usePotions("999A"));

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Protocole
Solution 2 Nina Scholz