有没有办法在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)]";
并且[___]部分被理解为在替换回字符串之前要解析的表达式。
感谢您的帮助。
答案 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}
已通过查找替换。您可以查看密钥,看看它是否是表达式,需要进行评估而不是简单地查找。评估是您真正的工作所在。
现在,您可以使用with
和eval
来获得表达支持;将上面的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
。)
但是你需要对这类事情保持谨慎,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 :(得分: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
;