Take a string snippet between () and change it in Javascript

Asked

Viewed 446 times

-1

I have a text string in the following format:

Size 35 (5 units)

I need to take the numbers inside the parentheses, run a function (which is already ready) and return a new number in place.

The problem is when the example is

Size 3 (3 units)

When I return the function, which is a subtraction, and there are two equal numbers, it updates the first number and not the one inside the parentheses, thus:

Size 2 (3 units)

And I need her to stay that way, in this example:

Size 3 (2 units)

My code is like this:

this.optionSelect = product.querySelectorAll("select");
//Lista todos os campos tipo SELECT
this.optionSelect.forEach(item => {
        let selectText = item.options[item.selectedIndex].innerText;
        //Pega o texto da tag OPTION
        let removePar = selectText.split("(");
        let replaceSelectQty = removePar.replace(/\D/g, '');


        for (let match of selectText.matchAll(/\([^)\d]*(\d+)[^)\d]*\)/g)) {
            var a = match[1];
            item.options[item.selectedIndex].innerText.replace(a, parseInt(replaceSelectQty)-parseInt(this.inputQty.value));
            //Atualiza o texto da tag OPTION, mas se o primeiro número for o mesmo da quantidade, ele atualiza o primeiro número e não a quantidade que está dentro dos parênteses
        }

    });

2 answers

2


You can change your regex by placing more capture groups (i.e., more snippets between parentheses). This creates more capture groups and allows you to make the correct stretch replacement:

function mudarNumero(n) { // uma função qualquer que muda o valor
    return parseInt(n) - 1;
}

let selectText = 'Tamanho 3 (3 Unidades)';
let novoTexto = selectText.replace(/(\([^)\d]*)(\d+)([^)\d]*\))/g,
    function(match, p1, p2, p3) {
        return `${p1}${mudarNumero(p2)}${p3}`;
    }
);
console.log(novoTexto); // Tamanho 3 (2 Unidades)

Now there are 3 sections in parentheses (and therefore 3 capture groups):

  1. (\([^)\d]*): the opening parentheses and zero or more characters which is not a number or ). I mean, it’s everything from the ( even before the number
  2. (\d+): one or more digits from 0 to 9
  3. ([^)\d]*\)): zero or more characters that is neither number nor ), followed by the closing parentheses. That is, it is all after the number until the ).

In the function passed as callback for replace, have the parameters p1, p2 and p3, which correspond respectively to the groups 1, 2 and 3 described above. The return of the function mounts another string with p1 and p3 without modification, and between them I call the function that modifies the value of p2 (which is the number in parentheses).

Thus the regex only replaces the number in parentheses, ignoring what is outside them.


If the string has several parentheses, and inside each one has more than one number, then the solution is a little different. In this case, I take each chunk between parentheses and then replace all the numbers within them:

function mudarNumero(n) { // uma função qualquer que muda o valor
    return parseInt(n) - 1;
}

let selectText = 'Tamanho 3 (3 Unidades 33 abc 3 xyz 44 def) lorem 4 ipsum (4 dolor 44 sit)';
let novoTexto = selectText;
// para cada conteúdo dentro de parênteses
for (const match of selectText.matchAll(/\(([^)]+)\)/g)) {
    // troca todos os números pelo retorno da função que muda o valor
    let s = match[1].replace(/(\d+)/g,
        function(match, p1) {
            return mudarNumero(p1);
        }
    );
    novoTexto = novoTexto.replace(`(${match[1]})`, `(${s})`);
}
console.log(novoTexto); // Tamanho 3 (2 Unidades 32 abc 2 xyz 43 def) lorem 4 ipsum (3 dolor 43 sit)

1

Following your approach, with few modifications, you could do so:

function go(){

            let select = document.querySelector("select");

            let currentSelectedOption = select.options[select.selectedIndex];
        
            let stringToHandle = currentSelectedOption.innerText;
        
            for (let match of stringToHandle.matchAll(/\([^)\d]*(\d+)[^)\d]*\)/g)) {
            
                let fullParentesisText = match[0];
                let number = match[1];

                let newFullParentesisText = fullParentesisText.replace(number, 
                    parseInt(number) - 2
                );

                let newFullText = stringToHandle.replace(fullParentesisText,
                    newFullParentesisText
                )

                currentSelectedOption.innerText = newFullText;
            
            }
        
        }
<select name="" id="">
    <option value="one">Tamanho 35 (5 Unidades)</option>
    <option value="two">Tamanho 3 (3 Unidades)</option>
</select>

<button onclick="go()">Go</button>

Browser other questions tagged

You are not signed in. Login or sign up in order to post.