diff --git a/readme.md b/readme.md index 007aed8..c761b36 100644 --- a/readme.md +++ b/readme.md @@ -73,6 +73,7 @@ var result = stringMath("2+2"); * `/` division sign * `+` plus sign * `-` subtraction sign + * `%` modulo sign * `(` and `)` parentheses ##### `callback` **[Function]** *(optional)* *(synchronous)* @@ -92,7 +93,7 @@ If the math formula is of correct type and is valid, it returns the [Number] res # Tips * the arithmetic **order of operations** is respected: * *parentheses first* - * *then division and multiplication (from left to right)* + * *then division, multiplication and modulo (from left to right)* * *then addition and subtraction (from left to right)* * the multiplication sign can be omitted before parentheses; `4(2+1)`; *equals to `4*(2+1)`* * the following signs combinations are allowed: diff --git a/string-math.js b/string-math.js index 80c74a2..06743cf 100644 --- a/string-math.js +++ b/string-math.js @@ -1,6 +1,6 @@ function stringMath(eq, callback) { if (typeof eq !== 'string') return handleCallback(new TypeError('The [String] argument is expected.'), null); - const mulDiv = /([+-]?\d*\.?\d+(?:e[+-]\d+)?)\s*([*/])\s*([+-]?\d*\.?\d+(?:e[+-]\d+)?)/; + const mulDivMod = /([+-]?\d*\.?\d+(?:e[+-]\d+)?)\s*([*/%])\s*([+-]?\d*\.?\d+(?:e[+-]\d+)?)/; const plusMin = /([+-]?\d*\.?\d+(?:e[+-]\d+)?)\s*([+-])\s*([+-]?\d*\.?\d+(?:e[+-]\d+)?)/; const parentheses = /(\d)?\s*\(([^()]*)\)\s*/; var current; @@ -14,21 +14,21 @@ function stringMath(eq, callback) { function fParentheses(eq) { while (eq.search(parentheses) !== -1) { eq = eq.replace(parentheses, function (a, b, c) { - c = fMulDiv(c); + c = fMulDivMod(c); c = fPlusMin(c); return typeof b === 'string' ? b + '*' + c : c; }); } - eq = fMulDiv(eq); + eq = fMulDivMod(eq); eq = fPlusMin(eq); return eq; } - function fMulDiv(eq) { - while (eq.search(mulDiv) !== -1) { - eq = eq.replace(mulDiv, function (a) { - const sides = mulDiv.exec(a); - const result = sides[2] === '*' ? sides[1] * sides[3] : sides[1] / sides[3]; + function fMulDivMod(eq) { + while (eq.search(mulDivMod) !== -1) { + eq = eq.replace(mulDivMod, function (a) { + const sides = mulDivMod.exec(a); + const result = sides[2] === '*' ? sides[1] * sides[3] : sides[2] === '/' ? sides[1] / sides[3] : sides[1] % sides [3]; return result >= 0 ? '+' + result : result; }); } diff --git a/tests/scenarios.js b/tests/scenarios.js index 897cfa0..8077e56 100644 --- a/tests/scenarios.js +++ b/tests/scenarios.js @@ -148,5 +148,27 @@ module.exports = [ {expression:".5e+123 * .25e-123",result:0.125}, {expression:"(2e+2)",result:200}, {expression:"123/1000/2000/3000",result:2.05e-8}, - {expression:"(2.5e-2*(.25e+2*(.05e+5*5e-2)))",result:156.25} -]; \ No newline at end of file + {expression:"(2.5e-2*(.25e+2*(.05e+5*5e-2)))",result:156.25}, + {expression:"10 % 3",result:1}, + {expression:"7 % 2",result:1}, + {expression:"15 % 4",result:3}, + {expression:"-10 % 3",result:-1}, + {expression:"-7 % 2",result:-1}, + {expression:"-15 % 4",result:-3}, + {expression:"10 % -3",result:1}, + {expression:"7 % -2",result:1}, + {expression:"15 % -4",result:3}, + {expression:"-10 % -3",result:-1}, + {expression:"-7 % -2",result:-1}, + {expression:"-15 % -4",result:-3}, + {expression:"(10 + 4) % 6",result:2}, + {expression:"15 % (3 + 2)",result:0}, + {expression:"(8 - 3) % (2 + 2)",result:1}, + {expression:"((7 % 3) + (4 % 2)) % 2",result:1}, + {expression:"10 % 3 + 5 % 2",result:2}, + {expression:"((8 % 3) + 4) % (2 % 2 + 1)",result:0}, + {expression:"((3 % 2) * 5) % 4",result:1}, + {expression:"(6 + 7 * 2) % (3 + 1 * 2)",result:0}, + {expression:"(9 % 4) * (6 % 2) - (8 % 3)",result:-2}, + {expression:"(((15 % 6) + 8) * 2) % 7",result:1} +];