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

1.5k Views Asked by At

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?

3

There are 3 best solutions below

1
Lonnie Best On BEST ANSWER

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

1
pavithran G On

you can use negative look-ahead and look-behind at the same time

const regex = /(?<![\w+])(months)(?![\w+])/gm;
const str = `months + 3 + (startmonths * 3) + months - (months*7) + (monthsend*5)`;
const subst = `12`;

const result = str.replace(regex, subst);
console.log('Substitution result: ', result);
3
Michał Turczyn On

I can suggest (^|[^a-z])month

Explanation:

(^|[^a-z]) - match beginning of a string ^ or (due to alternation |) antyhing except letters due to negated character class [^a-z], finally, store it inside first capturing group.

month = match month literally

Demo

EDIT: small correction: (^|[^a-z])month($|[^a-z])

$- match end of string

Replace it with \112\2 - \1 - first cuptruing group, \2 - second capturing group