Строка Javascript заменяется на вычисления - PullRequest
2 голосов
/ 16 мая 2010

Есть ли способ разрешить математические выражения в строках в JavaScript? Например, предположим, что я хочу создать строку «У Тома 2 яблока, у Люси 3 яблока. Вместе у них 5 яблок», но я хочу иметь возможность заменить переменные. Я могу сделать это с заменой строки:

string = "Tom has X apples, Lucy has Y apples. Together they have Z apples";
string2 = string.replace(/X/, '2').replace(/Y/, '3').replace(/Z/, '5');

Однако было бы лучше, если бы вместо переменной Z я мог использовать X + Y. Теперь я мог бы также заменить строку для X + Y и заменить ее на правильное значение, но это могло бы стать грязным, когда я попытался бы выполнить все возможные строковые вычисления, которые я мог бы сделать. Я полагаю, я ищу способ достичь этого:

string = "Something [X], something [Y]. Something [(X+Y^2)/(5*X)]";

И для того, чтобы части [___] понимались как выражения, которые должны быть разрешены до подстановки обратно в строку.

Спасибо за вашу помощь.

Ответы [ 4 ]

4 голосов
/ 16 мая 2010

Нет прямого, встроенного способа (ну, ладно, возможно, есть & mdash; см. Ниже), но если вы используете функцию обратного вызова функции replace, где замена может быть функцией, а не строкой (возвращаемое значение - это то, что подставлено), вы можете реализовать это довольно легко.

Например, предположим, что вы используете нотацию Ruby #{xyz} для ваших заполнителей. Этот код перебирает те, которые:

var mappings, str;

str = "One #{X} three #{Y} five";
mappings = {
    "X": 2,
    "Y": 4
};
str = str.replace(/\#\{([^#]+)\}/g, function(match, key) {
    var result;

    result = mappings[key];
    /* ...processing here */
    return result;
});

Результирующая строка - One 2 three 4 five, потому что #{X} и #{Y} были заменены поиском. Вы можете посмотреть на ключ и посмотреть, является ли оно выражением и его нужно оценивать, а не просто искать. Это оценка, где ваша настоящая работа приходит.

Теперь вы можете использовать with и eval для поддержки выражений; измените строку result = mapping[key]; выше на эту:

    with (mappings) {
        result = eval(key);
    }

Если вы введете туда строку "One #{X} three #{Y} five #{X + Y * 2}", результат будет One 2 three 4 five 10 & mdash; потому что 2 + 4 * 2 = 10.

Это работает, потому что with помещает данный объект поверх цепочки областей видимости, поэтому это первое, что проверяется при разрешении неквалифицированной ссылки (например, X), а eval выполняет код JavaScript & mdash; и поэтому может оценивать выражения & mdash; и волшебным образом делает это в объеме, в котором это называется. Но будьте осторожны; как указал Эрик, не все операторы одинаковы в различных формах выражения, и, в частности, Javascript интерпретирует ^ как «побитовый XOR», а не «в степени». (У него нет оператора экспоненты; вы должны использовать Math.pow.)

Но вы должны быть очень осторожны с такими вещами, и with и eval (каждый по-своему) могут быть проблематичными. Но основные проблемы с with заключаются в том, что трудно сказать, откуда что-то приходит и куда оно пойдет, если вы выполняете задание, а вы нет; и основные проблемы с eval связаны с его использованием для интерпретации строк, которые вы не контролируете. Пока вы сохраняете меры безопасности и знаете о проблемах ...

Сведение в функцию:

function evaluate(str, mappings) {
    return str.replace(/\#\{([^#]+)\}/g, function(match, key) {
        var result;

        with (mappings) {
            result = eval(key);
        }

        return result;
    });
}
alert(evaluate(
    "The expression '(#{X} + #{Y}) * 2' equals '#{(X + Y) * 2}'",
    {"X": 2, "Y": 4}
)); // alerts "The expression '(2 + 4) * 2' equals '12'"
alert(evaluate(
    "The expression '(#{X} + #{Y}) * 2' equals '#{(X + Y) * 2}'",
    {"X": 6, "Y": 3}
)); // alerts "The expression '(6 + 3) * 2' equals '18'"
1 голос
/ 16 мая 2010

Хороший вопрос:

function substitutestring(str,vals)
{
    var regex = /\[[^\]]*\]/gi;
    var matches = str.match(regex);
    var processed = [];

    for(var i = 0; i<matches.length; i++)
    {
        var match = matches[i];
        processed[match] = match.slice(1,-1);

        for(j in vals)
        {
            processed[match] = processed[match].replace(j,vals[j]);
        }

        processed[match] = eval("("+processed[match]+")");
    }

    for(var original in processed)
    {
        str = str.replace(original,processed[original]);
    }
    return str;
}

document.write(
    substitutestring(
        "[x] + [y] = [x+y]",
        {"x": 1, "y": 2}
    )
);
1 голос
/ 16 мая 2010

Единственный способ, которым я могу придумать, - это использовать движок шаблонов, такой как jTemplates . Также см. Ответы на этот ТАК вопрос.

0 голосов
/ 27 августа 2015

В ES6 теперь можно использовать строки шаблонов :

var X = 2, Y = 3; строка = Tom has ${X} apples, Lucy has ${Y} apples. Together they have ${X+Y} apples;

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...