本文介绍一种基于运算符优先级的表达式解析方案,解决原始代码中因未处理运算顺序导致的计算错误问题,支持形如 `5^; 1000 + 6^ - 5^ + 1` 的输入,并准确输出 `25 1012`。
原始实现的问题核心在于:它采用线性左结合扫描方式(类似 ((a op1 b) op2 c) ...),完全忽略了数学中的运算符优先级(如 + 和 - 优先级低于 *、/,而 ^ 在本题中是后缀一元操作符,需立即作用于前一个数),更未正确识别 X^ 这一特殊语法——它不是二元幂运算(如 2^3),而是后缀平方标记,仅表示“将前面的数字自乘”。
此外,原始代码中 tokens[i] === "^" && tokens[i + 1] === "" 的判断逻辑存在根本缺陷:正则分割 /(\+|\-|\*|\/|\^)/g 会把 6^ 拆成 ["6", "^", ""],但 "" 并非可靠标识;且 result = Math.pow(result, 2) 错误地将整个中间结果平方,而非仅对 6 或 5 等独立数字平方。
✅ 推荐采用分阶段 
利用正则全局替换,安全展开所有平方标记:
function expandSquares(input) {
return input.replace(/(\d+)\^/g, '$1 * $1');
}
// 示例:expandSquares("1000 + 6^ - 5^ + 1") → "1000 + 6 * 6 - 5 * 5 + 1"先处理 * 和 /(高优先级),再处理 + 和 -(低优先级)。每轮遍历,就地简化最左侧可计算的子表达式:
function evaluateMultiplicationDivision(expr) {
let tokens = expr.split(/([+\-*/])/).filter(t => t.trim() !== '');
for (let i = 1; i < tokens.length; i += 2) {
const op = tokens[i];
if (op === '*' || op === '/') {
const left = parseFloat(tokens[i - 1]);
const right = parseFloat(tokens[i + 1]);
const result = op === '*' ? left * right : left / right;
// 替换三个元素为结果
tokens.splice(i - 1, 3, result.toString());
i -= 2; // 重置索引,处理新生成的token
}
}
return tokens.join('');
}
function evaluateAdditionSubtraction(expr) {
let tokens = expr.split(/([+\-])/).filter(t => t.trim() !== '');
// 确保首项为正数(处理开头的负号)
if (tokens[0] === '-') {
tokens.splice(0, 2, '-' + tokens[1]);
}
for (let i = 1; i < tokens.length; i += 2) {
const op = tokens[i];
if (op === '+' || op === '-') {
const left = parseFloat(tokens[i - 1]);
const right = parseFloat(tokens[i + 1]);
const result = op === '+' ? left + right : left - right;
tokens.splice(i - 1, 3, result.toString());
i -= 2;
}
}
return tokens[0]; // 唯一剩余值即结果
}function calculateOne(expression) {
try {
const expanded = expandSquares(expression.trim());
const noMD = evaluateMultiplicationDivision(expanded);
const result = evaluateAdditionSubtraction(noMD);
return parseFloat(result).toString();
} catch (e) {
return "Error";
}
}
function calculate() {
const input = document.getElementById("input").value;
const expressions = input.split(';').map(e => e.trim()).filter(e => e);
const results = expressions.map(calculateOne);
document.getElementById("result").innerHTML = results.join(' ') + '
';
}输入:5^; 1000 + 6^ - 5^ + 1
⚠️ 注意事项:
该方法摒弃了脆弱的 token 索引推演,转而用语义明确的字符串变换与分层规约,大幅提升可读性与鲁棒性。
来电咨询