inside certain calculation I'm generating an math expression in javascript like
var myExpression = '';
if (!isNaN(myVal) && myVal> 0) {
myExpression += '(' + myVal+ ' * ' + someVal + ') +';
}
and based on certain user events I'm getting generated expression in console.log as you expect
(1 * 1) + (10 * 5) + ...
or
(10 * 5) + ...
How can I transform this math expression representation into real expression and to store it's result into variable?
You can use eval() on the string, which will run it as JavaScript. This will allow the math expression to be computed:
eval(myExpression);
Just note be wary of using eval(). See Why is using the JavaScript eval function a bad idea. Although that being said there are many things people can now do with the JavaScript built-in console, as users can execute any JavaScript they wish on any web page. See the third comment by of this answer byPrestaul on potential problems this can have. If you ensure that the variables cannot be directly manipulated by the user then your fine.
You can use math.js, which comes with it's own expression parser:
math.eval('(1 * 1) + (10 * 5)'); // 51
or provide variables in a scope and use them in the expression:
math.eval('(myVal * someVal)', {myVal: 2, someVal: 10}); // 20
you can also parse an expression into a tree and do operations on the tree, see docs:
http://mathjs.org/docs/expressions/parsing.html
http://mathjs.org/docs/expressions/expression_trees.html
Related
I want to transform the example string "0.45*100" in a value (45).
Another example, if I have two variables totalCost and contractVolume, and I have the string "totalCost * 1000 / contractVolume": how can I transform the string in the resulting value?
ex.
var totalCost = 10
var contractVolume = 100
var stringToCompute = "totalCost * 1000 / contractVolume"
console.log(compute(stringToCompute)) // -> 100
Obs:
I see a similar question, but in php, in the example he uses the method eval()
Url
you can also use eval() function in javascript
like --
eval("x + 17")
You can use eval() in JS too. Usually it is not a good idea if it is not mandatory, but it works.
What do you think about using looooooong regular expressions? Does this affect performance?
This is one of my regular expressions: (blockquote messed it up, so I edited it)
([(]((((-?((([0-9]+)|([(]-[0-9]+[)]))|(([0-9]*i)|([(]-[0-9]*i[)])))[*/]((([0-9]*i)|([(]-[0-9]*i[)]))|(([0-9]+)|([(]-[0-9]+[)]))))|(-?(([0-9]+)|([(]-[0-9]+[)]))[+-](([0-9]*i)|([(]-[0-9]*i[)]))[+-]((([0-9]*i)|([(]-[0-9]*i[)]))|(([0-9]+)|([(]-[0-9]+[)]))))|([(]((-?(([0-9]+)|([(]-[0-9]+[)]))[+-](([0-9]*i)|([(]-[0-9]*i[)])))|(-?(([0-9]*i)|([(]-[0-9]*i[)]))[+-](([0-9]+)|([(]-[0-9]+[)]))))[)][+/*-]([(]((-?(([0-9]+)|([(]-[0-9]+[)]))[+-](([0-9]*i)|([(]-[0-9]*i[)])))|(-?(([0-9]*i)|([(]-[0-9]*i[)]))[+-](([0-9]+)|([(]-[0-9]+[)]))))[)]|(([0-9]*i)|([(]-[0-9]*i[)]))|(([0-9]+)|([(]-[0-9]+[)]))))|(-?(([0-9]*i)|([(]-[0-9]*i[)]))[+/*-]((([0-9]*i)|([(]-[0-9]*i[)]))|[(]((-?(([0-9]+)|([(]-[0-9]+[)]))[+-](([0-9]*i)|([(]-[0-9]*i[)])))|(-?(([0-9]*i)|([(]-[0-9]*i[)]))[+-](([0-9]+)|([(]-[0-9]+[)]))))[)]))|(-?(([0-9]+)|([(]-[0-9]+[)]))[+/*-]((([0-9]+)|([(]-[0-9]+[)]))|[(]((-?(([0-9]+)|([(]-[0-9]+[)]))[+-](([0-9]*i)|([(]-[0-9]*i[)])))|(-?(([0-9]*i)|([(]-[0-9]*i[)]))[+-](([0-9]+)|([(]-[0-9]+[)]))))[)])))([+/*-](((-?((([0-9]+)|([(]-[0-9]+[)]))|(([0-9]*i)|([(]-[0-9]*i[)])))[*/]((([0-9]*i)|([(]-[0-9]*i[)]))|(([0-9]+)|([(]-[0-9]+[)]))))|(-?(([0-9]+)|([(]-[0-9]+[)]))[+-](([0-9]*i)|([(]-[0-9]*i[)]))[+-]((([0-9]*i)|([(]-[0-9]*i[)]))|(([0-9]+)|([(]-[0-9]+[)]))))|([(]((-?(([0-9]+)|([(]-[0-9]+[)]))[+-](([0-9]*i)|([(]-[0-9]*i[)])))|(-?(([0-9]*i)|([(]-[0-9]*i[)]))[+-](([0-9]+)|([(]-[0-9]+[)]))))[)][+/*-]([(]((-?(([0-9]+)|([(]-[0-9]+[)]))[+-](([0-9]*i)|([(]-[0-9]*i[)])))|(-?(([0-9]*i)|([(]-[0-9]*i[)]))[+-](([0-9]+)|([(]-[0-9]+[)]))))[)]|(([0-9]*i)|([(]-[0-9]*i[)]))|(([0-9]+)|([(]-[0-9]+[)]))))|(-?(([0-9]*i)|([(]-[0-9]*i[)]))[+/*-]((([0-9]*i)|([(]-[0-9]*i[)]))|[(]((-?(([0-9]+)|([(]-[0-9]+[)]))[+-](([0-9]*i)|([(]-[0-9]*i[)])))|(-?(([0-9]*i)|([(]-[0-9]*i[)]))[+-](([0-9]+)|([(]-[0-9]+[)]))))[)]))|(-?(([0-9]+)|([(]-[0-9]+[)]))[+/*-]((([0-9]+)|([(]-[0-9]+[)]))|[(]((-?(([0-9]+)|([(]-[0-9]+[)]))[+-](([0-9]*i)|([(]-[0-9]*i[)])))|(-?(([0-9]*i)|([(]-[0-9]*i[)]))[+-](([0-9]+)|([(]-[0-9]+[)]))))[)])))|(([0-9]*i)|([(]-[0-9]*i[)]))|(([0-9]+)|([(]-[0-9]+[)]))|[(]((-?(([0-9]+)|([(]-[0-9]+[)]))[+-](([0-9]*i)|([(]-[0-9]*i[)])))|(-?(([0-9]*i)|([(]-[0-9]*i[)]))[+-](([0-9]+)|([(]-[0-9]+[)]))))[)]))*)|(((([0-9]*i)|([(]-[0-9]*i[)]))|(([0-9]+)|([(]-[0-9]+[)]))|[(]((-?(([0-9]+)|([(]-[0-9]+[)]))[+-](([0-9]*i)|([(]-[0-9]*i[)])))|(-?(([0-9]*i)|([(]-[0-9]*i[)]))[+-](([0-9]+)|([(]-[0-9]+[)]))))[)])([+/*-]((-?((([0-9]+)|([(]-[0-9]+[)]))|(([0-9]*i)|([(]-[0-9]*i[)])))[*/]((([0-9]*i)|([(]-[0-9]*i[)]))|(([0-9]+)|([(]-[0-9]+[)]))))|(-?(([0-9]+)|([(]-[0-9]+[)]))[+-](([0-9]*i)|([(]-[0-9]*i[)]))[+-]((([0-9]*i)|([(]-[0-9]*i[)]))|(([0-9]+)|([(]-[0-9]+[)]))))|([(]((-?(([0-9]+)|([(]-[0-9]+[)]))[+-](([0-9]*i)|([(]-[0-9]*i[)])))|(-?(([0-9]*i)|([(]-[0-9]*i[)]))[+-](([0-9]+)|([(]-[0-9]+[)]))))[)][+/*-]([(]((-?(([0-9]+)|([(]-[0-9]+[)]))[+-](([0-9]*i)|([(]-[0-9]*i[)])))|(-?(([0-9]*i)|([(]-[0-9]*i[)]))[+-](([0-9]+)|([(]-[0-9]+[)]))))[)]|(([0-9]*i)|([(]-[0-9]*i[)]))|(([0-9]+)|([(]-[0-9]+[)]))))|(-?(([0-9]*i)|([(]-[0-9]*i[)]))[+/*-]((([0-9]*i)|([(]-[0-9]*i[)]))|[(]((-?(([0-9]+)|([(]-[0-9]+[)]))[+-](([0-9]*i)|([(]-[0-9]*i[)])))|(-?(([0-9]*i)|([(]-[0-9]*i[)]))[+-](([0-9]+)|([(]-[0-9]+[)]))))[)]))|(-?(([0-9]+)|([(]-[0-9]+[)]))[+/*-]((([0-9]+)|([(]-[0-9]+[)]))|[(]((-?(([0-9]+)|([(]-[0-9]+[)]))[+-](([0-9]*i)|([(]-[0-9]*i[)])))|(-?(([0-9]*i)|([(]-[0-9]*i[)]))[+-](([0-9]+)|([(]-[0-9]+[)]))))[)]))))+))[)])
Can i use RegExp this length or is it bad practise?
EDIT
I'm constructing complex number calculator. This regex is made from shorter ones. This is how i am doing it:
var regularExpression = new (function()
{
this.re = "(([0-9]+)|([(]-[0-9]+[)]))",
this.im = "(([0-9]*i)|([(]-[0-9]*i[)]))",
this.complexNumber = "[(]((-?"+ this.re + "[+-]" + this.im + ")|(-?" + this.im + "[+-]" + this.re +"))[)]",
this.expression = "("+
"(-?("+this.re+"|"+this.im+")[*/]("+this.im+"|"+this.re+"))|"+
"(-?"+this.re+"[+-]"+this.im+"[+-]("+this.im+"|"+this.re+"))|"+
"("+this.complexNumber+"[+/*-]("+this.complexNumber+"|"+this.im+"|"+this.re+"))|"+
"(-?"+this.im+"[+/*-](" + this.im+"|"+this.complexNumber+"))|"+
"(-?"+this.re+"[+/*-](" + this.re+"|"+this.complexNumber+"))"+
")",
this.simpleExpression = "([(]("+
"("+this.expression+"([+/*-]("+this.expression+"|"+this.im+"|"+this.re+"|"+this.complexNumber+"))*)|"+
"(("+this.im+"|"+this.re+"|"+this.complexNumber+")([+/*-]"+this.expression+")+)"+
")[)])"
})();
So my regularExpression.simpleExpression is even longer, because is uses expression few times. Thats why I'm asking and worried.
simpleExpression is looking for strings like: (12321-12231i+1233123*(12i-231)+12323-i)
Regular expressions are very fast, when they are written in a good manner (definitely much faster than e.g. the code based on conditionals).
However, the question you should ask yourself is whether the code is maintainable and readable - someone may have to rewrite this part of the code in the future and even you might not understand it at first glance after some time.
First point from here might answer your question: https://hackernoon.com/few-simple-rules-for-good-coding-my-15-years-experience-96cb29d4acd9
What's the best way to do insert variables in a string in JavaScript? I'm guessing it's not this:
var coordinates = "x: " + x + ", y: " + y;
In Java, Strings are immutable and doing something like the above would unnecessarily create and throw away Strings. Ruby is similar and has a nice way of doing the above:
coordinates = "x: #{x}, y: #{y}"
Does something similar exist for JavaScript?
Introduced in ES6 as "template strings"
MDN docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
const name = "Nick"
const greeting = `Hello ${name}` // "Hello Nick"
That's fine in JavaScript. There is no good built-in equivalent of an sprintf or String.format, however, you can build your own.
Don't worry about the "unnecessary" string objects. That's definitely micro-optimization. Address it if and when you need that extra tiny bit of performance or memory optimization, but in distributed software, you probably don't.
https://www.npmjs.com/package/stringinject
https://github.com/tjcafferkey/stringinject
I created this function to do exactly this, it will allow you to pass in a string, and an object with keys that will replace placeholder values in the string with their values like below:
var str = stringInject("My username is {username} on {platform}", { username: "tjcafferkey", platform: "GitHub" });
// My username is tjcafferkey on Github
If for some reason you are doing this many times per second and referencing the strings many times per call, you can always store the strings themselves as variables.
var preX = 'x: '
, preY = 'y: '
, coords
;
coords = preX + x + preY + y;
This of course should be supported by benchmarking/profiling, but creating many strings per frame is often a source of unnecessary garbage which can result in jank down the line.
I have a number which currently is 1,657,108,700 and growing. However I wish for it to show as
1,657,108k
Does javascript or html have a build in function to do this?
The value is being set throu javascript to a span field in html.
[edit]
From the comment I got my method as far as:
var start = '1,657,108,700';
start = (start / 1000).toFixed(0);
var finish = '';
while (start.length > 3)
{
finish = ','.concat(start.substring(start.length - 3, 3), finish);
start = start.substring(0, start.length - 3);
};
finish = start + finish + "k";
return finish;
however this returns 1,65,7k instead of 1,657,108k.. anyone know why?
var formattedNumber = Math.round(yourNumber / 1000).toLocaleString() + "k";
Turn the above into a function or not as appropriate. I'm not aware of a single function to do this, or of a way to cater for non-English versions of "k" (assuming there are some), but at least toLocaleString() should take care of the comma versus fullstop for thousands issue.
UPDATE: I posted the above without testing it; when I tried it out I found toLocaleString() formatted 1234 as 1,234.00. I had thought of fixing it by using a regex replace to remove trailing zeros except of course I can't be sure what character toLocaleString() is going to use for the decimal point, so that won't work. I guess you could write some code that uses toLocaleString() on a "control" number (e.g., 1.1) to see at runtime what character it uses for the decimal.
UPDATE 2 for your updated question, inserting the commas manually, I did it like this:
var unformattedNumber = 123456;
var a = unformattedNumber.toString().split("");
for (var i=a.length-3; i >0; i-=3)
a.splice(i,0,",");
var formattedNumber = a.join("") + "k";
I'm creating a GreaseMonkey script to improve the user interface of the 10k tools Stack Overflow uses. I have encountered an unreproducible and frankly bizarre problem that has confounded me and the others in the JavaScript room on SO Chat. We have yet to find the cause after several lengthy debugging sessions.
The problematic script can be found here. Source - Install
The problem occurs at line 85, the line after the 'vodoo' comment:
return (t + ' (' + +(+f.offensive + +f.spam) + ')');
It might look a little weird, but the + in front of the two variables and the inner bracket is for type coercion, the inner middle + is for addition, and the other ones are for concatenation.
Nothing special, but observant reader might note that type coercion on the inner bracket is unnecessary, since both are already type coerced to numbers, and type coercing result is useless when they get concatenated into a string anyway. Not so! Removing the + breaks the script, causing f.offensive and f.spam to be concatenated instead of added together.
Adding further console.log only makes things more confusing:
console.log(f.offensive + f.spam); // 50
console.log('' + (+f.offensive + +f.spam)); // 5, but returning this yields 50 somehow
console.log('' + (+f.offensive + +f.spam) + ''); // 50
Source: https://chat.stackoverflow.com/transcript/message/203261#203261
The problem is that this is unreproducible - running scripts like
console.log('a' + (+'3' + +'1') + 'b');
in the Firebug console yields the correct result, as does
(function(){
return 'a' + (+'3' + +'1') + 'b';
})();
Even pulling out large chunks of the code and running them in the console does not reproduce this bug:
$('.post-menu a[id^=flag-post-]').each(function(){
var f = {offensive: '4', spam: '1'};
if(f){
$(this).text(function(i, t){
// Vodoo - please do not remove the '+' in front of the inner bracket
return (t + ' (' + +(+f.offensive + +f.spam) + ')');
});
}
});
Tim Stone in the chatroom has reproduction instruction for those who are below 10k.
This bug only appears in Firefox - Chrome does not appear to exhibit this problem, leading me to believe that this may be a problem with either Firefox's JavaScript engine, or the Greasemonkey add-on. Am I right?
I can be found in the JavaScript room if you want more detail and/or want to discuss this.
As part of the userscript's process, a <script> tag is injected into the page with the code retrieved by calling toString() on the function you've defined. Usually this would be fine, but it appears that there's a bug in the javascript engine used by Firefox 3.6.13 that relocates the parentheses in the expression, causing it to be evaluated in a very different way when the toString()-ified function is processed.
To illustrate this problem, we can run the following code in Firebug:
function f() { var a = '', b = '1', c = '2'; return a + '(' + (+b + +c) + ')'; };
f.toString();
This gives us this output:
function f() {
var a = "", b = "1", c = "2";
return a + ("(" + + b + + c + ")");
}
You'll note that the return expression has been modified. The parentheses have been relocated beyond the strings that were previously outside of them, causing the variables b and c to be coerced to strings and concatenated. This gives an unexpected result, since the expected addition never takes place. Unfortunately, this behaviour is present even when using Number() or parseInt() to coerce b and c.
There are several small modifications which change this, but the clearest is simply to save the result of the addition to a variable beforehand:
$(this).text(function(i, t){
var c = +f.offensive + +f.spam;
return (t + ' (' + c + ')');
});
Thankfully, this problem seems to not occur in the Firefox 4 beta, so hopefully this issue has been resolved going forward. Also, Matthew Flaschen has graciously gone ahead and filed a bug report (marked duplicate of 559438) so that the developers are made aware of this issue in either case.