Parse arithmetic expression with javascript - javascript

Is there a simple way, with javascript, to convert the following expression
e*((a*(b+c))+d)
into something like
multiply(e, add(multiply(a, add(b,c)), d))
The expression would be stored in a string. I'm open to any solution that will avoid me to write my own parser (library, buitl-in capabilities, ...)
EDIT: I should have precised that I don't actually want to use multiply and add functions, the purpose of this is to define my own function to replace multiply and add and perform custom operations on the variables

The expression you are trying to parse into an abstract syntax tree is a context-free expression. This means that you need a context-free grammar to be able to parse it. So let's create a parser.
To simplify the parsing we'll separate the lexical analysis phase. Hence the first thing we need is to create a lexer. Luckily there are a lot of handy lexer libraries available. We'll use the this one:
https://github.com/aaditmshah/lexer
So here's the lexical analyzer:
var lexer = new Lexer;
lexer.addRule(/\s+/, function () {
/* skip whitespace */
});
lexer.addRule(/[a-z]/, function (lexeme) {
return lexeme; // symbols
});
lexer.addRule(/[\(\+\-\*\/\)]/, function (lexeme) {
return lexeme; // punctuation (i.e. "(", "+", "-", "*", "/", ")")
});
Next we create a parser. We'll use the following implementation of Dijkstra's shunting yard algorithm for parsing:
https://gist.github.com/aaditmshah/6683499
So here's the parser:
var factor = {
precedence: 2,
associativity: "left"
};
var term = {
precedence: 1,
associativity: "left"
};
var parser = new Parser({
"+": term,
"-": term,
"*": factor,
"/": factor
});
Finally we create a parse function as follows:
function parse(input) {
lexer.setInput(input);
var tokens = [], token;
while (token = lexer.lex()) tokens.push(token);
return parser.parse(tokens);
}
Now you simply call parse to get a parsed stream of tokens in postfix notation:
var output = parse("e*((a*(b+c))+d)");
alert(output.join(" ")); // "e a b c + * d + *"
The advantage of postfix form is that you can easily manipulate it using a stack:
Push e onto the stack.
Push a onto the stack.
Push b onto the stack.
Push c onto the stack.
Pop b and c and push b + c onto the stack.
Pop a and b + c and push a * (b + c) onto the stack.
Push d onto the stack.
Pop a * (b + c) and d and push a * (b + c) + d onto the stack.
Pop e and a * (b + c) + d and push e * (a * (b + c) + d) onto the stack.
Similarly it's easy to create the output you want using stacks too. It the same steps. You only push different values back onto the stack for different operations.
See the demo: http://jsfiddle.net/d2UYZ/2/
Edit 1: I was so bored that I solved the problem for you:
var stack = [];
var operator = {
"+": "add",
"-": "subtract",
"*": "multiply",
"/": "divide"
};
parse("e*((a*(b+c))+d)").forEach(function (c) {
switch (c) {
case "+":
case "-":
case "*":
case "/":
var b = stack.pop();
var a = stack.pop();
stack.push(operator[c] + "(" + a + ", " + b + ")");
break;
default:
stack.push(c);
}
});
var output = stack.pop();
alert(output);
The output is (as you expect) the string "multiply(e, add(multiply(a, add(b,c)), d))". See the demo: http://jsfiddle.net/d2UYZ/4/
Edit 2: If you need to evaluate the expression you could do that easily too. All you need is a context mapping symbols to values and functions for each operator:
var stack = [];
var context = {
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5
};
var operator = {
"+": function (a, b) { return a + b; },
"-": function (a, b) { return a - b; },
"*": function (a, b) { return a * b; },
"/": function (a, b) { return a / b; }
};
parse("e*((a*(b+c))+d)").forEach(function (c) {
switch (c) {
case "+":
case "-":
case "*":
case "/":
var b =+ stack.pop();
var a =+ stack.pop();
stack.push(operator[c](a, b));
break;
default:
stack.push(context[c]);
}
});
var output = stack.pop();
Thus the expression e*((a*(b+c))+d) becomes 5*((1*(2+3))+4) which evaluates to 45. See the demo: http://jsfiddle.net/d2UYZ/6/

You cannot do this with eval as has been suggested, because you would not be able to use your custom add and multiply functions that way. You could parse out all of the operators with regular expressions, but it would not be easy.
You would have to make sure you got the order of operations correct, and break it into many steps.
The basic logic of it would be:
Define your add and multiply functions.
Define a function that takes a string of numbers and operators (without parentheses) and splits it into binary operations (ie. '1 + 7' or '5 * 3') with regular expressions, that can be passed to your add and multiply functions. This would have to be done recursively, following your desired order of operations for your custom math, in other words, if you get '5 + 3 * 2' you will have parse out '3 * 2' and evaluate that before using its result to add to 5 (assuming your order would be multiply first).
Define a function that looks for parentheses and recursively finds the innermost set and passes it to function 2 above to be evaluated.
Pass your input string to function 3 above and hope that you got all of the recursive logic and regular expressions correct.

I think the better way is define your own functions like this:
multiply = function(a, b) {
return a * b;
}
add = function(a, b) {
return a + b;
}
This examples is limited to only two numbers, but it can be scaled using arguments.
Fiddle

Related

Writing a calculator function - in the most functional programming way(javascript)

I am trying out a task from codewars and wanted to write in a functional programming way in javascript. I have some questions regarding my functions and how the code can be written in a better way.
The task itself is to build a calculator function. It will accept an input in the format:
'..... + ...'
The calculator must split the string by the middle character signifying the operation and then the two string that are left will be the two values. In the example above first value will be 5 and the second 3. Once this is done, depending on the operator, do the action - either addition, multiplication etc.
Here is my code:
function dotCalculator(equation) {
function returnSymbol(input) {
if (input.includes(' + ')) {
return ' + ';
} else if (input.includes(' - ')) {
return ' - ';
} else if (input.includes(' * ')) {
return ' * ';
} else if (input.includes(' / ')) {
return ' / ';
}
}
let symbolOf = returnSymbol;
let result = equation.split(symbolOf(equation)).map(x => x.length);
// Array.prototype.add = function(){
// return this[0] + this[1];
// }
}
I know my code is not done yet. I am trying to understand how to properly finish it having the functional programming way of thinking in mind. Maybe prototypal inheritance would a bit overkill. I am looking for some ideas from anyone who would lend a hand. I tried writing a more complex reduce after
let arrMine = equation.split(symbolOf(equation)).map((x) => x.length);
but it seemed way too messy. Any help would be greatly appreciated.
I'm very much a functional programming noob, the pipe function being here is probably kind of gratuitous and I might have taken the ..... + ... example overly literally, but here's an attempt:
const arith = {
'+': (a, b) => a + b,
'-': (a, b) => a - b,
'*': (a, b) => a * b,
'/': (a, b) => a / b,
};
const pipe = (...fns) => (arg) => fns.reduce((res, fn) => fn(res), arg);
const get_input_elements = (input) => input.split(' ');
const get_number = (dots) => dots.length;
const get_numbers = ([str_a, op, str_b]) =>
[get_number(str_a), op, get_number(str_b)];
const apply_arith = ([a, op, b]) => arith[op](a, b);
const calc = pipe(
get_input_elements,
get_numbers,
apply_arith
);
console.log(calc('..... + ...'));
console.log(calc('..... - ...'));
console.log(calc('...... / ..'));
In this example are functional programs that can evaluate simple arithmetic -- adding, subtracting, multiplying, or dividing two numbers.
Details are commented in example below
Note: prefix any negative number being passed into calc() with an underscore _ instead of a hyphen -
// Utility function
const log = data => console.log(JSON.stringify(data));
// Arithmetic functions
const sum = (a, b) => (+a) + (+b);
const dif = (a, b) => a - b;
const pro = (a, b) => a * b;
const quo = (a, b) => a / b;
/**
* Calculate a simple formula a+b, a-b, a*b, or a/b.
* #param {string} formula - Pattern:
* "numberOPERANDnumber" ex. "5+5"
* Use an underscore to prefix negative numbers.
* #returns {number} Result of formula
*/
const calc = formula => {
// Declare variables
let result, f, a, b, op;
/*
Convert string into an array of strings.
[number, operand, number]
Replace any _ with - (see #param)
*/
f = formula.split(/([+\-*/])/)
.map(ab => ab.replace('_', '-'));
/*
Convert string of numbers into real numbers.
*/
a = parseFloat(f[0]);
b = parseFloat(f[2]);
op = f[1];
/*
Check if >a< and >b< are real numbers and if the input string was split
into 3 strings.
*/
if (Number.isNaN(a) || Number.isNaN(b) || f.length != 3) {
return;
}
// >op< determines the method of resolving the formula
switch (op) {
case '+':
result = sum(a, b);
break;
case '-':
result = dif(a, b);
break;
case '*':
result = pro(a, b);
break;
case '/':
result = quo(a, b);
break;
default:
return;
}
return result;
};
log(calc('5+5'));
log(calc('_10-7')); // That's a -10 (see #param)
log(calc('5*9'));
log(calc('51/3'));

compare math equations prior to evaluation javascript

I'm running through algebra and attempting to create a JavaScript tester function which compares two equations and determines if they are considered associative properties. In other words, if I group (a + b) + c vs. a + (b + c) the result will be the same. Multiplication and addition only.
Up to this point, I've attempted to build a simple function that resolves whether the final value is equal to the compared equation value. What I would like is if I was able to compare both equations without their parenthesis. Thinking I need to look up regular expressions... but looking for a little help on direction.
let a = 1,
b = 2,
c = 3,
number1 = (a * b) * c,
number2 = a * (b * c);
function isAssociative(num1, num2) {
let answer = num1 === num2;
return `Are ${num1} and ${num2} associative... ${answer}`;
}
console.log(isAssociative(number1, number2));
Currently, this results in, 'Are 6 and 6 associative... true'. This is what I want, but if I changed the second argument to a static 6 when calling the function... then this is not an associative combo and I would like it to return false.
You can use Mathjs and the simplify method:
console.clear();
term_a = 'a + ( b + c )'
term_b = '( a + b ) + c';
tree_a = math.simplify(term_a);
tree_b = math.simplify(term_b);
console.log(term_a, tree_a.equals(tree_b) ? 'equals' : 'differs from', term_b);
term_a = 'a + ( b + c + d )'
term_b = '( a + b ) + c';
tree_a = math.simplify(term_a);
tree_b = math.simplify(term_b);
console.log(term_a, tree_a.equals(tree_b) ? 'equals' : 'differs from', term_b);
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/5.4.2/math.min.js"></script>
I found an answer I'm satisfied with.
let number1 = prompt('Enter an equation').toString().replace(/[^0-9,+,*]+/g,''),
number2 = prompt('Enter equation 2').toString().replace(/[^0-9,+,*]+/g,'');
function isAssociative (num1, num2) {
if (num1 === num2) {
return eval(num1) === eval(num2);
} else {
return false;
}
}
alert(isAssociative(number1, number2));
I could wait for the numbers to enter the function as a string, check for parenthesis first to verify it even qualifies... if parenthesis exist, then I could execute the regEx code and if they don't exist return 'not associative' at that point. For now, this works as well as I want it to.

JavaScript - Is there a way to find out whether the given characters are contained in a string without looping?

I have an array of combinations from 5 characters (order within a combination plays no role):
AB, ABDE, CDE, C, BE ...
On its basis I need to validate the input from user. The entered combination of characters should be contained in one of the combinations of the array.
If user enters "ADE" or "CE" the result should be yes, if e.g. "BCE" - no.
In a trivial case, when entered combination simply matches the one in array, I can use .inArray. If entered combination consists of neighbors, I can do .indexOf. How to be in the case above?
One of the solutions would be to extend the initial array by including all possible "child" combinations. Is there an alternative?
The first thing I could think of is grep'ping the array with a regex match.
var haystack = ["BCED","DBCE","CEB","ECBA","CB","BDCA"];
var needle = "CBE";
var re = new RegExp("(?=.*" + needle.split('').join(")(?=.*") + ").{" + needle.length+"}");
console.log(re);
console.log($.grep(haystack, function(str){
return str.match(re,"g");
}));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I'll expand on the comment I've made to the quesion above: If you have a small number of fixed set elements, you can represent the sets as binary masks. So say you have the original sets as strings:
var sset = ["AB", "ABDE", "CDE", "C", "BE"];
Create a dictionary of possible elements and bits. The bits are powers of two, which can be created by bit-shifting: 1 << n is bit n:
dict = {
A: (1 << 0),
B: (1 << 1),
C: (1 << 2),
D: (1 << 3),
E: (1 << 4),
};
That dictionary can then be used to create the bitmask:
function bitmask(s, d) {
let res = 0;
for (let i = 0; i < s.length; i++) {
res |= d[s[i]]
}
return res;
}
Create a companion array to the sets that contains the masks:
var mset = sset.map(function(x) { return bitmask(x, dict); });
If you want to check an input, cnvert it to a mask first and then run the checks. A set s contains all bits of an input x if (s & x) == x:
var s = "ADE";
var m = bitmask(s, dict);
for (let i = 0; i < mset.length; i++) {
console.log(sset[i], s, (mset[i] & m) == m);
}
You can use this strategy for several conditions:
• (a & b) == b — all elements of b are contained in a;
• (a & b) == 0 — a and b have no common elements;
• (a & b) != 0 — at least one elements of b is in a;
• a == b — the sets a and b are identical.
In set parlance a & b is the intersection, a | b is the union and a ^ b is the symmetric difference of a and b.
As far as I know, jQuery is a library written in Javascript, so all bit-wise operators should be available.

How do I add two numbers in JavaScript "without using `+` or `-` operators"?

I know an alternative to using the + sign for addition is to do something like this:
int add(int a, int b)
{
if(b == 0)
return sum;
sum = a ^ b;
carry = (a & b) << 1;
return add(sum,carry);
}
But I have two problems:
This is C++, not JavaScript. Is this supported in JavaScript?
It's obvious the whole trick is in ^ & <<, but I don't know how to start looking for them in JavaScript, because I don't know what they are called.
What should I be googling for even?
I tried to write this in JavaScript ... but seems I miss something
var getSum = function(a, b) {
return (a ^ b, (a & b) << 1)
};
We will use bitwise operators and will use recursion.
We use this method when we have a few low resources. Read more about when to use this method!
var getSum = function(a, b) {
if (b == 0) {
return a;
} else {
return getSum(a ^ b, (a & b) << 1)
}
};
ECMAScript 6 one-liner solution as suggested by #PatrickRoberts:
const getSum = (a,b) => b ? getSum(a ^ b, (a & b) << 1) : a;
Another solutions:
2- Arrays technique Array.prototype.fill()
const getSum = (a, b) => {
const firstArr = new Array(a).fill(true);
const secondArr = new Array(b).fill(true);
return firstArr.concat(secondArr).length
}
3- workaround to use plus sign without writing it:
const getSum = (a, b) => eval(''.concat(a).concat(String.fromCharCode(0x2B)).concat(b));
Well ok i am answering to the question as clearly described in the header. No + and no - operations right..? Yet... not with bitwise but with pure math should be a valid answer i suppose.
var x = 1,
y = 2,
sum = Math.log2(2**x * 2**y);
console.log(sum);
const add = (a, b) => new Function('a', 'b', `return ${a} ${String.fromCharCode(43)} ${b}`)(a, b);
We can implement same using while loop. We have to shift the carry to left and add it to binary sum of numbers till there will no carry. (As we follows the practice in addition of decimals.)
function getSum(a, b){
while(b!=0){
var carry = a&b; //calculate if is there any carry we need to add
a = a^b; // a is used to hold the sum
b = carry<<1; //b is used to hold left shift carry
}
return a;
}
document.write(getSum(7, 5))
It's possible to use arrays structures to perform a sum operation.
function getSum(a, b){
return Array(a).concat(Array(b)).length / 100;
}
Each input is coerced to an array, for instance, an input of value 5 would be coerced to an array of 5 elements. After coercing both inputs, the arrays are joined into a single array. The length of the final array is returned, by dividing to 100 to deal with the sum of decimal values.
Now, let's try to be defensive about invalid input cases, such as strings or falsy values.
const DEFAULT_NUMBER_VALUE = 0;
const DEFAULT_PRECISION = 100;
function parseAddInput(input){
if (!input) {
return DEFAULT_NUMBER_VALUE;
}
if (typeof input === 'string'){
input = parseInt(input);
}
const roundedNumber = Math.round(input * (10 * DEFAULT_PRECISION));
return roundedNumber;
}
function getSum(a, b){
return Array(
parseAddInput(a)
).concat(
Array(parseAddInput(b))
).length / 100;
}
function add(number1, number2){
return getSum(number1, number2);
}
The same approach as #PatrickRoberts suggested, but without recursion:
const add = (a, b) => {
let c;
while (a !== 0) {
c = b & a;
b = b ^ a;
c = c << 1;
a = c;
}
return b;
};

comma syntax javascript

Can someone help me understand what the next line means? What is -
elem,.style.height = ( pos /100) * h + "px";
There's a comma right after elem.
function slideDown( elem ){
//
elem.style.height = '0px';
show(elem);
var h = fullHeight(elem);
for (var i = 0 ; i <= 100; i+= 5){
(function(){
var pos = i;
setTimeout(function(){
elem,.style.height = ( pos /100) * h + "px";
}, (pos + 1) * 10 );
})();
}
}
But let's explain the comma punctuator in JavaScript, shall we? :)
The comma can be either a separator or an operator. As a separator, it appears in these scenarios:
function foo(x, y, z) { /* function body */ }
foo(1, 2, 3);
var obj = { name: "John", surname: "Smith", age: 35 };
var arr = [1, 2, 3];
var x = 1, y = 2, z = 3;
This is not a complete list, but I think I covered the most popular scenarios (separating formal parameters in function declarations/expressions, arguments in function calls, object literal items, array literal items, and variable declarations).
As a operator, the comma can be used to list expressions:
x = 1, foo(), location.href, bar(), x = 2;
The comma operator should be avoided (" except for very disciplined use in the control part of for statements" - Crockford, http://javascript.crockford.com/code.html)
It is a typo, but it's also almost valid syntax.
The comma may be used to separate statements, returning the last. So this is valid:
a = 3;
a, b = 4;
However, the .style in the second clause of the comma is invalid syntax (vars cannot begin with period, and style is not defined, so it can't have the property of height).
Remove the comma.
A comma will have the role of operator outside a string. Your example is clearly a mistake.
You can use the comma operator when you want to include multiple expressions in a location that requires a single expression. The most common usage of this operator is to supply multiple parameters in a for loop.
Source: MDC

Categories

Resources