заменить имена переменных на string.replace(регулярное выражение, значение)

Попытка сделать то, что я считал довольно простой заменой строки, оказалась более сложной, чем я думал.

Если у меня есть строка вроде

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

Для ясности, "формула", которую я анализирую, предоставляется пользователем и может состоять из любых серий имен переменных, операторов (+*/-) и скобок, которые пользователь может придумать. Что мне нужно сделать, так это сначала заменить переменные числами, а затем оценить полученное выражение.,

я ищу, как заменить все вхождения слов месяцев, скажем, "12" с помощью функции string.replace.

Так что, надеюсь, результат функции будет

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

Похоже, мне нужно регулярное выражение, чтобы избежать замены в строках, таких как "startmonths", возможно, у меня сложилось впечатление, что на самом деле это невозможно сделать в регулярном выражении javascript, потому что "lookbehind" редко поддерживаются в современных браузерах.

Я пробовал использовать [^A-Za-z9-9_](months)(?:[^A-Za-z0-9_])но это захватывает символ до и после месяца, поэтому я не могу использовать его в качестве параметра для string.replace.

Есть ли какое-то обходное решение, или мне нужно забыть о функции замены и сделать это "вручную" с помощью поиска, соединения и т. Д.?

3 ответа

Решение

Кажется, это работает без необходимости смотреть назад или вперед:

let regExMonth = /\bmonths\b/gm;
let str = "months + 3 + (startmonths * 3) + months - (months*7) + (monthsend*5)";

str = str.replace(regExMonth, "12");
console.log(str);

Скриншот с сайта regexr.com:

Вы правы, что ретроспективы работают не везде. Однако они работают в Chrome и скоро будут работать в Firefox. В спецификации 2018 года были добавлены ретроспективы, поэтому жаль, что они еще не стали повсеместными в 2020 году.

Там, где поддерживается просмотр назад, я бы использовал как "отрицательный взгляд назад", так и "отрицательный взгляд вперед", например:

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

Сокращение приведенного выше будет:

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

Скриншот с сайта regexr.com:

Я могу предложить (^|[^a-z])month

Пояснение:

(^|[^a-z]) - сопоставить начало строки ^ или (из-за чередования |) antyhing, кроме букв, из-за отрицательного класса символов [^a-z]и, наконец, сохраните его в первой группе захвата.

month = совпадение month буквально

Демо

РЕДАКТИРОВАТЬ: небольшая поправка: (^|[^az]) месяц ($|[^az])

$- сопоставить конец строки

Замени его на \112\2 - \1 - первая группа, \2 - вторая группа захвата

Вы можете использовать отрицательный взгляд вперед и назад одновременно

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);
Другие вопросы по тегам