Skip to content

Instantly share code, notes, and snippets.

Created April 22, 2014 03:08
Show Gist options
  • Save anonymous/11164160 to your computer and use it in GitHub Desktop.
Save anonymous/11164160 to your computer and use it in GitHub Desktop.
A Pen by Alan R. Soares.
<div class='container' ng-app='evaluator'>
<div class='page-header'>
<h1><span class='text-muted'>Simple</span> Arithmetic Expression Evaluator</h1>
</div>
<form name='evtForm' role="form" class='well' ng-controller='AppCtrl' action='#'>
<div class="form-group has-feedback"
ng-class="{false: 'has-error', true:'has-success'}[evtForm.expression.$valid]">
<label class='control-label'
for="expression">Expression</label>
<input id='expression'
name='expression'
class="form-control"
ng-model='expression'
ng-pattern='/(\d+(\.\d+)?)(\s+)?([\^*\/\+-])(\s+)?(\d+(\.\d+)?)/'
required
placeholder='enter expression' />
<span class="glyphicon glyphicon-ok form-control-feedback"
ng-class="{true:'glyphicon-ok', false:'glyphicon-remove'}[evtForm.$valid]"></span>
<div class='alert alert-danger'
ng-show='!evtForm.$valid'>
Invalid Expression!
</div>
</div>
<div class='form-group'
ng-show='evtForm.$valid'>
<label class='control-label'>Result</label>
<div class='alert alert-info'>
{{result}}
</div>
</div>
<div class='form-group'
ng-show='steps'>
<label class='control-label'>Steps</label>
<ul>
<li ng-repeat='step in steps'>
{{step}}
</li>
</ul>
</div>
</form>
</div>
var app = angular.module('evaluator', [])
.controller('AppCtrl', function ($scope, expressionEvaluator) {
var ee = expressionEvaluator;
var onExpressionChange = function (newValue, oldValue) {
if (newValue !== oldValue && ee.isValid(ee.sanitize(newValue))) {
ee.resetSteps();
$scope.steps = [];
evaluate(newValue);
}
};
function evaluate(newValue){
$scope.steps = [];
$scope.result = ee.evaluate(newValue || $scope.expression);
$scope.steps = ee.getSteps();
}
(function init() {
$scope.steps = [];
$scope.$watch('expression', onExpressionChange);
$scope.expression = "3 ^ (3 + (1 + 2 - 3)) * 4 / 5";
evaluate();
}());
})
.factory('expressionEvaluator', function () {
var mathPatt = /(\d+(\.\d+)?)([\^*\/\+-])(\d+(\.\d+)?)/;
var precPatt0 = /(\d+(\.\d+)?)(\^)(\d+(\.\d+)?)/;
var precPatt1 = /(\d+(\.\d+)?)([*\/])(\d+(\.\d+)?)/;
var subExprPatt = /(?:\()([\d\.\+\/-]+)(?:\))/;
var steps = [];
function getSteps(){
return steps;
}
function resetSteps(){
steps = [];
}
function addStep(step){
steps.push(step);
}
function isValid(expr) {
return mathPatt.test(expr);
}
function sanitize(expr) {
return expr.trim().replace(/\s+/ig, '');
}
function getNextSegment(expr) {
return precPatt0.exec(expr) || precPatt1.exec(expr) || mathPatt.exec(expr);
}
function hasSubExpression(expr) {
return subExprPatt.test(expr);
}
function getSubExpression(expr) {
return subExprPatt.exec(expr);
}
function evaluateSegment(segment) {
var operator = segment[3];
var elm1 = parseFloat(segment[1]);
var elm2 = parseFloat(segment[4]);
switch (operator) {
case "^":
return Math.pow(elm1, elm2);
case "*":
return elm1 * elm2;
case "/":
return elm1 / elm2;
case "+":
return elm1 + elm2;
case "-":
return elm1 - elm2;
}
}
function replaceSegmentResult(segment, result) {
return segment.input.replace(segment[0], result.toString());
}
function evaluate(expression) {
var expr = sanitize(expression);
var lastItem = steps.length >0 ? steps[steps.length-1] : "";
if(!/sub/.test(lastItem))
addStep("evaluating expression: " + expr);
var result;
while (hasSubExpression(expr)) {
var subExprSegment = getSubExpression(expr);
var subExpression = subExprSegment[1];
addStep("sub expression: " + subExprSegment[0]);
result = evaluate(subExpression);
expr = replaceSegmentResult(subExprSegment, result);
}
while (isValid(expr)) {
addStep('segment: ' + expr);
var segment = getNextSegment(expr);
result = evaluateSegment(segment);
expr = replaceSegmentResult(segment, result);
}
var res = parseFloat(expr);
addStep('result: ' + res);
return res;
}
return {
evaluate: evaluate,
isValid: isValid,
sanitize: sanitize,
getSteps: getSteps,
resetSteps: resetSteps
};
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment