Javascript字符串替换为计算

时间:2010-05-16 11:03:56

标签: javascript string

有没有办法在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 个答案:

答案 0 :(得分:4)

没有直接的,内置的方式(好吧,好吧,也许有 - 见下文),但是如果你使用replace函数的回调功能,那么替换可以是一个函数而不是一个函数string(返回值是替换的),你可以很容易地实现它。

例如,假设您使用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}已通过查找替换。您可以查看密钥,看看它是否是表达式,需要进行评估而不是简单地查找。评估是您真正的工作所在。

现在,您可以使用witheval来获得表达支持;将上面的result = mapping[key];行更改为:

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

如果您将字符串"One #{X} three #{Y} five #{X + Y * 2}"输入其中,则结果为One 2 three 4 five 10 - 因为2 + 4 * 2 = 10。

这是有效的,因为with将给定对象粘贴在作用域链的顶部,所以这是解析非限定引用时检查的第一件事(如X),而eval执行Javascript代码 - 所以可以计算表达式 - 并且在它被调用的范围内神奇地这样做。但要注意;正如埃里克指出的那样,并非所有运算符在各种表达形式中都是相同的,特别是Javascript将^解释为“按位异或”,而非“强制”。 (它没有指数运算符;您必须使用Math.pow。)

但是你需要对这类事情保持谨慎,witheval(每个都以他们自己的方式)可能会有问题。但是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 :(得分:1)

我能想到实现这一目标的唯一方法就是模仿引擎,例如jTemplates。另请参阅this问题的答案。

答案 2 :(得分:1)

好问题:

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}
    )
);

答案 3 :(得分:0)

在ES6中,您现在可以使用template strings

var X = 2,Y = 3; string = Tom has ${X} apples, Lucy has ${Y} apples. Together they have ${X+Y} apples;