Search code examples
javascriptregexecmascript-2018

replace variable names with string.replace(regex, value)


Trying to do what I thought was a fairly simple string replacement, but turns out to be more complicated than I thought.

If I have a string like

months + 3 + (startmonths * 3) + months - (months*7) + (monthsend*5)

For clarity, the "formula" I am parsing is user supplied, and can consist of any series of variables names and operators (+*/-) and parens that that a user can come up with. What I will need to do is first replace the variables with numbers and then evaluate the resulting expression.,

what I am looking for is how to replace all occurrences of the words months with, say "12" using string.replace function.

So hopefully the output of the function is

 12 + 3 + (startmonths * 3) + 12 - (12*3) + (monthsend*5)"

It seems like I need a regex to avoid replacing in strings like "startmonths", I am maybe under the impression its actually not possible to do in javascript regex because the "lookbehinds" are sparsely supported across modern browsers.

I tried using [^A-Za-z9-9_](months)(?:[^A-Za-z0-9_]) but that captures the character preceding and following 'months', so I can't use it as a parameter to string.replace.

Is there some workaround, or do I have to forget the replace function and do it "by hand" with find and splice etc?


Solution

  • This seems to work without needing look-behinds or look-aheads:

    let regExMonth = /\bmonths\b/gm;
    let str = "months + 3 + (startmonths * 3) + months - (months*7) + (monthsend*5)";
    
    str = str.replace(regExMonth, "12");
    console.log(str);

    Screenshot from regexr.com: enter image description here

    You're right that the look-behinds don't work everywhere yet. However, they do work in Chrome, and they'll be working in Firefox soon. Look-behinds were added in the 2018 specification, so it is shameful that they are not yet ubiquitous here in 2020.

    Where look-behinds are supported, I'd use a both a "negative look-behind" and a "negative look-ahead" too like this:

    (?<![A-Za-z0-9_])(months)(?![A-Za-z0-9_])
    

    Shorthand of above would be:

    (?<![\w])(months)(?![\w])
    

    Screenshot from regexr.com: enter image description here