From c6973847aa8da916712bcf1848ad9cad17a93861 Mon Sep 17 00:00:00 2001 From: Mahdi Dibaiee Date: Thu, 18 Jun 2015 16:14:13 +0430 Subject: [PATCH] Add support for NumVariable expressions such as 2x fixes #6 --- README.md | 4 ++- dist/index.js | 61 ++++++++++++++++++++++++++++++++++-------- dist/tests/equation.js | 5 ++++ lib/index.js | 58 ++++++++++++++++++++++++++++++++------- tests/equation.js | 5 ++++ 5 files changed, 111 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 6e5b222..ddc3b81 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,10 @@ console.log(Equation.solve('4 * lg(4) ^ 3')); // 32 // equation let sphereArea = Equation.equation('4 * PI * r^2'); - console.log(sphereArea(5)); // 314.1592653589793 + +let test = Equation.equation('2x + 6y'); +console.log(test(4, 3)).to.equal(8 + 18); ``` You can also register your own operators and constants. diff --git a/dist/index.js b/dist/index.js index 91f3301..a47e75f 100644 --- a/dist/index.js +++ b/dist/index.js @@ -70,14 +70,14 @@ var Equation = { */ equation: function equation(expression) { var stack = parseExpression(expression); + console.log(stack); var variables = []; stack.forEach(function varCheck(a) { if (Array.isArray(a)) { return a.forEach(varCheck); } - - if (typeof a === 'string' && !_.isNumber(a) && !_operators2['default'][a] && a === a.toLowerCase()) { + if (isVariable(a)) { // grouped variables like (y) need to have their parantheses removed variables.push(_.removeSymbols(a)); } @@ -88,15 +88,30 @@ var Equation = { args[_key] = arguments[_key]; } - expression = expression.replace(/[a-z]*/g, function (a) { + stack.forEach(function varCheck(a, i, arr) { + if (Array.isArray(a)) { + return a.forEach(varCheck); + } + var index = variables.indexOf(a); if (index > -1) { - return args[index] || 0; + // grouped variables like (y) need to have their parantheses removed + arr[i] = args[index]; } - return a; }); - return Equation.solve(expression); + stack = sortStack(stack); + stack = _.parseNumbers(stack); + stack = solveStack(stack); + // expression = expression.replace(/[a-z]*/g, a => { + // let index = variables.indexOf(a); + // if (index > -1) { + // return args[index] || 0; + // } + // return a; + // }); + + return stack; }; }, @@ -154,12 +169,15 @@ var MIN_PRECEDENCE = Math.min.apply(Math, _toConsumableArray(PRECEDENCES)); var parseExpression = function parseExpression(expression) { var stream = new _ReadStream2['default'](expression), stack = [], - record = ''; + record = '', + cur = undefined, + past = undefined; // Create an array of separated numbers & operators while (stream.next()) { - var cur = stream.current(), - past = stack.length - 1; + cur = stream.current(); + past = stack.length - 1; + if (cur === ' ') { continue; } @@ -169,8 +187,14 @@ var parseExpression = function parseExpression(expression) { record += cur; } else if (record.length) { + var beforeRecord = past - (record.length - 1); + if (isVariable(record) && _.isNumber(stack[beforeRecord])) { + stack.push('*'); + } stack.push(record, cur); record = ''; + + // numbers and decimals } else if (_.isNumber(stack[past]) && (_.isNumber(cur) || cur === '.')) { stack[past] += cur; @@ -199,6 +223,10 @@ var parseExpression = function parseExpression(expression) { } } if (record.length) { + var beforeRecord = past - (record.length - 1); + if (isVariable(record) && _.isNumber(stack[beforeRecord])) { + stack.push('*'); + } stack.push(record); } @@ -437,5 +465,16 @@ var fixFloat = function fixFloat(number) { return +number.toFixed(15); }; -exports['default'] = Equation; -module.exports = exports['default']; \ No newline at end of file +/** + * Recognizes variables such as x, y, z + * @param {String} a + * The string to check for + * @return {Boolean} + * true if variable, else false + */ +var isVariable = function isVariable(a) { + return typeof a === 'string' && !_.isNumber(a) && !_operators2['default'][a] && a === a.toLowerCase(); +}; + +exports.isVariable = isVariable; +exports['default'] = Equation; \ No newline at end of file diff --git a/dist/tests/equation.js b/dist/tests/equation.js index e269e4b..c018fbb 100644 --- a/dist/tests/equation.js +++ b/dist/tests/equation.js @@ -30,6 +30,11 @@ describe('Equations', function () { _expect.expect(equation).to['throw'](); }); + it('should work with NumVariable expressions like 2x', function () { + var equation = _M2['default'].equation('2x + 6y'); + _expect.expect(equation(4, 3)).to.equal(8 + 18); + }); + it('Test case', function () { var equation = _M2['default'].equation('2+x*(y+4)+z^2'); _expect.expect(equation(2, 4, 3)).to.equal(27); diff --git a/lib/index.js b/lib/index.js index 41cb438..8fb0e3e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -47,30 +47,44 @@ let Equation = { */ equation(expression) { let stack = parseExpression(expression); + console.log(stack); let variables = []; stack.forEach(function varCheck(a) { if (Array.isArray(a)) { return a.forEach(varCheck); } - - if (typeof a === 'string' && !_.isNumber(a) && - !operators[a] && a === a.toLowerCase()) { + if (isVariable(a)) { // grouped variables like (y) need to have their parantheses removed variables.push(_.removeSymbols(a)); } }); return function(...args) { - expression = expression.replace(/[a-z]*/g, a => { + stack.forEach(function varCheck(a, i, arr) { + if (Array.isArray(a)) { + return a.forEach(varCheck); + } + let index = variables.indexOf(a); if (index > -1) { - return args[index] || 0; + // grouped variables like (y) need to have their parantheses removed + arr[i] = args[index]; } - return a; }); - return Equation.solve(expression); + stack = sortStack(stack); + stack = _.parseNumbers(stack); + stack = solveStack(stack); + // expression = expression.replace(/[a-z]*/g, a => { + // let index = variables.indexOf(a); + // if (index > -1) { + // return args[index] || 0; + // } + // return a; + // }); + + return stack; }; }, @@ -118,12 +132,14 @@ const MIN_PRECEDENCE = Math.min(...PRECEDENCES); const parseExpression = expression => { let stream = new ReadStream(expression), stack = [], - record = ''; + record = '', + cur, past; // Create an array of separated numbers & operators while (stream.next()) { - const cur = stream.current(), - past = stack.length - 1; + cur = stream.current(); + past = stack.length - 1; + if (cur === ' ') { continue; } @@ -134,8 +150,14 @@ const parseExpression = expression => { record += cur; } else if (record.length) { + let beforeRecord = past - (record.length - 1); + if (isVariable(record) && _.isNumber(stack[beforeRecord])) { + stack.push('*'); + } stack.push(record, cur); record = ''; + + // numbers and decimals } else if (_.isNumber(stack[past]) && (_.isNumber(cur) || cur === '.')) { @@ -165,6 +187,10 @@ const parseExpression = expression => { } } if (record.length) { + let beforeRecord = past - (record.length - 1); + if (isVariable(record) && _.isNumber(stack[beforeRecord])) { + stack.push('*'); + } stack.push(record); } @@ -341,4 +367,16 @@ const fixFloat = number => { return +number.toFixed(15); }; +/** + * Recognizes variables such as x, y, z + * @param {String} a + * The string to check for + * @return {Boolean} + * true if variable, else false + */ +export const isVariable = a => { + return typeof a === 'string' && !_.isNumber(a) && + !operators[a] && a === a.toLowerCase(); +}; + export default Equation; diff --git a/tests/equation.js b/tests/equation.js index f4e7e77..81a36ec 100644 --- a/tests/equation.js +++ b/tests/equation.js @@ -23,6 +23,11 @@ describe('Equations', () => { expect(equation).to.throw(); }); + it('should work with NumVariable expressions like 2x', () => { + let equation = M.equation('2x + 6y'); + expect(equation(4, 3)).to.equal(8 + 18); + }); + it('Test case', () => { let equation = M.equation('2+x*(y+4)+z^2'); expect(equation(2, 4, 3)).to.equal(27);