This calculator simulates the evaluation of basic Excel formulas. Excel is a powerful spreadsheet program that allows users to perform various calculations using built-in functions and standard arithmetic operators. This tool focuses on a simplified interpretation of how some common Excel operations work.
How it Works:
You input an Excel-like formula and provide a JSON object representing your cell values. The calculator then attempts to parse and evaluate the formula based on these values.
Quickly checking calculations without opening Excel.
Understanding how specific Excel functions operate.
Verifying small datasets or formula logic.
Limitations:
This is a simplified calculator. It does not support:
Complex Excel features (e.g., Pivot Tables, Charts, VBA).
All Excel functions (only a few basic ones are implemented).
Advanced range expressions (e.g., 3D references, named ranges).
Error handling for all possible Excel scenarios (e.g., #DIV/0!, #REF!).
Boolean logic (AND, OR, etc.).
Text manipulation functions (LEFT, RIGHT, CONCATENATE).
function getCellValue(cellRef, cellData) {
if (!cellRef || typeof cellData !== 'object' || cellData === null) {
return NaN;
}
var value = cellData[cellRef];
if (value === undefined || value === null) {
return NaN; // Treat undefined/null cells as invalid for calculation
}
var numericValue = parseFloat(value);
return isNaN(numericValue) ? NaN : numericValue;
}
function evaluateRange(rangeStr, cellData) {
var values = [];
var parts = rangeStr.split(':');
if (parts.length !== 2) return [];
var startCol = parts[0].match(/[A-Z]+/)[0];
var startRow = parseInt(parts[0].match(/\d+/)[0]);
var endCol = parts[1].match(/[A-Z]+/)[0];
var endRow = parseInt(parts[1].match(/\d+/)[0]);
var startColCode = startCol.charCodeAt(0);
var endColCode = endCol.charCodeAt(0);
for (var r = startRow; r <= endRow; r++) {
for (var cCode = startColCode; cCode <= endColCode; cCode++) {
var colLetter = String.fromCharCode(cCode);
var cellRef = colLetter + r;
var cellValue = getCellValue(cellRef, cellData);
if (!isNaN(cellValue)) {
values.push(cellValue);
}
}
}
return values;
}
function evaluateExpression(expression, cellData) {
expression = expression.trim();
// Handle simple numbers
var num = parseFloat(expression);
if (!isNaN(num)) {
return num;
}
// Handle cell references
if (/^[A-Z]+\d+$/.test(expression)) {
var val = getCellValue(expression, cellData);
return isNaN(val) ? 0 : val; // Default to 0 if cell not found or not a number
}
// Handle functions
var sumMatch = expression.match(/^SUM\((.+)\)$/i);
if (sumMatch) {
var args = sumMatch[1];
if (args.includes(':')) { // Range SUM
var rangeValues = evaluateRange(args, cellData);
var total = 0;
for (var i = 0; i < rangeValues.length; i++) {
total += rangeValues[i];
}
return total;
} else { // List SUM
var values = args.split(',').map(function(val) { return val.trim(); });
var total = 0;
for (var i = 0; i < values.length; i++) {
var cellVal = evaluateExpression(values[i], cellData);
if (!isNaN(cellVal)) {
total += cellVal;
}
}
return total;
}
}
var averageMatch = expression.match(/^AVERAGE\((.+)\)$/i);
if (averageMatch) {
var args = averageMatch[1];
var numericArgs = [];
if (args.includes(':')) { // Range AVERAGE
numericArgs = evaluateRange(args, cellData);
} else { // List AVERAGE
var values = args.split(',').map(function(val) { return val.trim(); });
for (var i = 0; i < values.length; i++) {
var cellVal = evaluateExpression(values[i], cellData);
if (!isNaN(cellVal)) {
numericArgs.push(cellVal);
}
}
}
if (numericArgs.length === 0) return 0;
var sum = 0;
for (var i = 0; i < numericArgs.length; i++) {
sum += numericArgs[i];
}
return sum / numericArgs.length;
}
var maxMatch = expression.match(/^MAX\((.+)\)$/i);
if (maxMatch) {
var args = maxMatch[1];
var numericArgs = [];
if (args.includes(':')) { // Range MAX
numericArgs = evaluateRange(args, cellData);
} else { // List MAX
var values = args.split(',').map(function(val) { return val.trim(); });
for (var i = 0; i < values.length; i++) {
var cellVal = evaluateExpression(values[i], cellData);
if (!isNaN(cellVal)) {
numericArgs.push(cellVal);
}
}
}
if (numericArgs.length === 0) return NaN;
return Math.max.apply(null, numericArgs);
}
var minMatch = expression.match(/^MIN\((.+)\)$/i);
if (minMatch) {
var args = minMatch[1];
var numericArgs = [];
if (args.includes(':')) { // Range MIN
numericArgs = evaluateRange(args, cellData);
} else { // List MIN
var values = args.split(',').map(function(val) { return val.trim(); });
for (var i = 0; i < values.length; i++) {
var cellVal = evaluateExpression(values[i], cellData);
if (!isNaN(cellVal)) {
numericArgs.push(cellVal);
}
}
}
if (numericArgs.length === 0) return NaN;
return Math.min.apply(null, numericArgs);
}
// Handle arithmetic operations (simple ones, may need more robust parsing for complex nesting)
if (expression.includes('+')) {
var parts = expression.split('+');
if (parts.length === 2) {
var left = evaluateExpression(parts[0], cellData);
var right = evaluateExpression(parts[1], cellData);
return isNaN(left) || isNaN(right) ? NaN : left + right;
}
}
if (expression.includes('-')) {
var parts = expression.split('-');
if (parts.length === 2) {
var left = evaluateExpression(parts[0], cellData);
var right = evaluateExpression(parts[1], cellData);
return isNaN(left) || isNaN(right) ? NaN : left – right;
}
}
if (expression.includes('*')) {
var parts = expression.split('*');
if (parts.length === 2) {
var left = evaluateExpression(parts[0], cellData);
var right = evaluateExpression(parts[1], cellData);
return isNaN(left) || isNaN(right) ? NaN : left * right;
}
}
if (expression.includes('/')) {
var parts = expression.split('/');
if (parts.length === 2) {
var left = evaluateExpression(parts[0], cellData);
var right = evaluateExpression(parts[1], cellData);
if (isNaN(left) || isNaN(right) || right === 0) return NaN; // Handle division by zero
return left / right;
}
}
return NaN; // If no match found
}
function calculateExcelFormula() {
var formula = document.getElementById("formulaInput").value;
var cellValuesJson = document.getElementById("cellValuesInput").value;
var resultDiv = document.getElementById("result");
resultDiv.textContent = ""; // Clear previous result
if (!formula) {
resultDiv.textContent = "Error: Please enter a formula.";
return;
}
var cellData = {};
try {
cellData = JSON.parse(cellValuesJson);
if (typeof cellData !== 'object' || cellData === null) {
throw new Error("Invalid JSON format for cell values.");
}
} catch (e) {
resultDiv.textContent = "Error: Invalid JSON format for cell values. " + e.message;
return;
}
// Basic substitution and evaluation
var evaluatedResult = evaluateExpression(formula, cellData);
if (isNaN(evaluatedResult)) {
resultDiv.textContent = "Calculation Error or Invalid Input";
} else {
resultDiv.textContent = "Result: " + evaluatedResult.toFixed(4); // Display result with 4 decimal places
}
}