This is a basic calculator function. It only does addition, subtraction, multiplication, division and parentheses.
I'm having an infinite loop on recursive call in while section which is checking the string whether has a parentheses or not. If i would've send a string with 2 or more parentheses to the function, it has been stucking in loop. I couldn't figure out what I have done wrong.
const operators = ['+', '-', '*', '/', '(', ')'];
const numbers = [];
let arr;
const array = [];
function Calculate(string) {
string.split('').map(char => {
if (!operators.includes(char)) {
numbers.push(char);
} else {
arr = numbers.join('');
numbers.splice(0);
array.push(arr, char);
}
});
arr = numbers.join('');
const str = array.filter(char => char !== '').concat(arr);
while (str.includes('(')) { // Checking parentheses
let indexOpen = str.findIndex(char => char === '(');
let indexClose = indexOpen + 1;
let count = 1;
while (count !== 0) {
if (str[indexClose] === '(') {
count++;
} else if (str[indexClose] === ')') {
count--;
}
indexClose++;
}
if (
!operators.includes(str[indexOpen - 1])
// str[indexOpen - 1] !== '+' &&
// str[indexOpen - 1] !== '-' &&
// str[indexOpen - 1] !== '*' &&
// str[indexOpen - 1] !== '/'
) {
str.splice(indexOpen, 0, '*');
indexOpen++;
indexClose++;
}
const strPara = str
.filter((_, i) => i < indexClose - 1 && i > indexOpen)
.join('');
str.splice(indexOpen, indexClose - indexOpen, Calculate(strPara));
}
let indexMul; // Multiplication and division
let indexDiv;
while (str.includes('*') || str.includes('/')) {
indexMul =
str.findIndex(char => char === '*') === -1
? str.length
: str.findIndex(char => char === '*');
indexDiv =
str.findIndex(char => char === '/') === -1
? str.length
: str.findIndex(char => char === '/');
if (indexMul < indexDiv) {
str.splice(indexMul - 1, 3, +str[indexMul - 1] * +str[indexMul + 1] + '');
} else if (indexDiv < indexMul) {
str.splice(
indexDiv - 1,
3,
Math.trunc(+str[indexDiv - 1] / +str[indexDiv + 1]) + ''
);
}
}
while (str.length !== 1) { // Addition and subtraction
if (str[1] === '+') {
str.splice(0, 3, +str[0] + +str[2] + '');
}
if (str[1] === '-') {
str.splice(0, 3, +str[0] - +str[2] + '');
}
}
return str;
}
console.log(Calculate('3(16-(10-4)+2)/2(4*2)+1'));
I did this.
Be careful, this code does the calculations one after the other without managing operators precedence
The recursive way :
let strCalc = '3(16-(10-4)+2)/2(4*2)+1'
document.write(`${ strCalc } = ${ Calculate(strCalc) }`)
document.write(`<br><br>`)
strCalc = '5 ( -18.4 + 2 ) / ( -2 ( 4 * -.5 )) + 1'
document.write(`${ strCalc } = ${ Calculate(strCalc) }`)
function Calculate(str)
{
const ops = str
.match(/[\(\)\+\-\*\/]|((\d+\.?\d*)|(\.\d+))/g)
.reduce((r,v)=>
{
if (isNaN(v))
{
if (!r.opPrev || v==='(')
{
r.res.push(v)
r.opPrev = ( v!==')' )
}
else if (v==='-') // check negatives values
r.sign='-';
}
else
{
r.res.push(Number(`${r.sign}${v}`))
r.sign = ''
r.opPrev = false
}
return r
}, { res:[], opPrev:true, sign:'' }).res
;
let Pos = 0
;
return makeCalc()
;
function makeCalc()
{
let result = 0
, operand = '+'
, val
;
while ( Pos < ops.length && ops[Pos] !== ')' )
{
val = ops[Pos]
;
if ( val === '(' )
{
operand ??= '*' // nullish assignement operator
Pos++
val = makeCalc() // recurvive call
}
if ( isNaN(val) )
operand = val
;
else
{
switch (operand)
{
case '+' : result += val; break;
case '-' : result -= val; break;
case '/' : result /= val; break; // may do 0 divide!
case '*' : result *= val; break;
}
operand = null
}
Pos++
}
return result
}
}