Files

34 lines
1.6 KiB
JavaScript

// 원가 및 단가산출의 사칙연산·괄호·[항목명] 참조를 평가한다.
const EstFormula = (() => {
function evaluate(expression, values) {
const tokens = expression.match(/\s+|\d+(?:\.\d+)?|\[[^\]]+\]|[()+*/-]/g) || [];
if (tokens.join('') !== expression) throw Error('지원하지 않는 수식 문자');
const items = tokens.filter(t => !/^\s+$/.test(t));
let i = 0;
function primary() {
const token = items[i++];
if (token === '(') { const n = sum(); if (items[i++] !== ')') throw Error('괄호 오류'); return n; }
if (token === '-') return -primary();
if (token === '+') return primary();
if (/^\d/.test(token || '')) return Number(token);
if (token?.startsWith('[')) { const key=token.slice(1,-1); if (!Object.hasOwn(values,key)) throw Error(`참조 항목 없음: ${key}`); return values[key]; }
throw Error('수식 오류');
}
function product() {
let n = primary();
while (items[i] === '*' || items[i] === '/') { const op=items[i++], v=primary(); if (op === '/' && v === 0) throw Error('0으로 나눌 수 없음'); n=op === '*' ? n*v : n/v; }
return n;
}
function sum() {
let n = product();
while (items[i] === '+' || items[i] === '-') { const op=items[i++], v=product(); n=op === '+' ? n+v : n-v; }
return n;
}
const result=sum();
if (i !== items.length || !Number.isFinite(result)) throw Error('수식 오류');
return result;
}
return { evaluate };
})();
if (typeof module !== 'undefined') module.exports = EstFormula;