34 lines
1.6 KiB
JavaScript
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;
|