Is there a way to resolve mathematical expressions in strings in javascript? For example, suppose I want to produce the string “Tom has 2 apples, Lucy has 3 apples. Together they have 5 apples” but I want to be able to substitute in the variables. I can do this with a string replacement:
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');
However, it would be better if, instead of having a variable Z, I could use X+Y. Now, I could also do a string replace for X+Y and replace it with the correct value, but that would become messy when trying to deal with all the possible in-string calculations I might want to do. I suppose I’m looking for a way to achieve this:
string = "Something [X], something [Y]. Something [(X+Y^2)/(5*X)]";
And for the [___] parts to be understood as expressions to be resolved before substituting back into the string.
Thanks for your help.
There’s no direct, built-in way (well, okay, perhaps there is — see below), but if you use the callback feature of the
replacefunction, where the replacement can be a function rather than a string (the return value is what’s substituted in), you can implement this fairly easily.For instance, suppose you use the Ruby notation
#{xyz}for your placeholders. This code loops through those:The resulting string is
One 2 three 4 five, because#{X}and#{Y}have been replaced via lookup. You can look at the key and see whether it’s an expression and needs to be evaluated rather than simply looked up. That evaluation is where your real work comes in.Now, you could use
withandevalto achieve expression support; change theresult = mapping[key];line above to this:If you feed the string
"One #{X} three #{Y} five #{X + Y * 2}"into that, the result isOne 2 three 4 five 10— because2 + 4 * 2= 10.That works because
withsticks the given object on top of the scope chain, so it’s the first thing checked when resolving an unqualified reference (likeX), andevalexecutes Javascript code — and so can evaluate expressions — and magically does so within the scope in which it’s called. But beware; as Eric pointed out, not all operators are the same in various forms of expression, and in particular Javascript interprets^to mean “bitwise XOR”, not “to the power of”. (It doesn’t have an exponent operator; you have to useMath.pow.)But you need to be very careful about that sort of thing, both
withandeval(each in their own way) can be problematic. But the main issues withwithare that it’s hard to tell where something comes from or where it will go if you do an assignment, which you’re not; and the main issues withevalcome from using it to interpret strings you don’t control. As long as you keep safeguards in place and are aware of the issues…Boiling that down into a function: