|
@@ -1,69 +1,231 @@
|
|
|
+import Decimal from "decimal.js";
|
|
|
+import { ElMessage } from "element-plus";
|
|
|
+
|
|
|
+// class Counter {
|
|
|
+// private result: Decimal;
|
|
|
+
|
|
|
+// constructor() {
|
|
|
+// this.result = new Decimal(0);
|
|
|
+// }
|
|
|
+
|
|
|
+// // 加法
|
|
|
+// addition(val: number | string): this {
|
|
|
+// this.result = this.result.plus(new Decimal(val));
|
|
|
+// return this;
|
|
|
+// }
|
|
|
+
|
|
|
+// // 减法
|
|
|
+// subtraction(val: number | string): this {
|
|
|
+// this.result = this.result.minus(new Decimal(val));
|
|
|
+// return this;
|
|
|
+// }
|
|
|
+
|
|
|
+// // 乘法
|
|
|
+// multiplication(val: number | string): this {
|
|
|
+// this.result = this.result.times(new Decimal(val));
|
|
|
+// return this;
|
|
|
+// }
|
|
|
+
|
|
|
+// // 除法
|
|
|
+// division(val: number | string): this {
|
|
|
+// if (new Decimal(val).isZero()) {
|
|
|
+// throw new Error("除数不能为零");
|
|
|
+// }
|
|
|
+// this.result = this.result.dividedBy(new Decimal(val));
|
|
|
+// return this;
|
|
|
+// }
|
|
|
+
|
|
|
+// // 计算表达式
|
|
|
+// calculate(expression: string): this {
|
|
|
+// const tokens = this.tokenize(expression);
|
|
|
+// const parsedExpression = this.parse(tokens);
|
|
|
+// this.result = new Decimal(this.evaluate(parsedExpression));
|
|
|
+// return this;
|
|
|
+// }
|
|
|
+
|
|
|
+// // 获取结果
|
|
|
+// get(): number {
|
|
|
+// return this.result.toNumber(); // 返回普通数字
|
|
|
+// }
|
|
|
+
|
|
|
+// // 词法分析,将字符串分割为token
|
|
|
+// private tokenize(expression: string): Array<string> {
|
|
|
+// return expression.match(/(\d+(\.\d+)?|[-+*/()])/g) || [];
|
|
|
+// }
|
|
|
+
|
|
|
+// // 解析表达式
|
|
|
+// private parse(tokens: Array<string>): Array<Decimal | string> {
|
|
|
+// const output: Array<Decimal | string> = [];
|
|
|
+// const operators: Array<string> = [];
|
|
|
+// const precedence: { [key: string]: number } = {
|
|
|
+// "+": 1,
|
|
|
+// "-": 1,
|
|
|
+// "*": 2,
|
|
|
+// "/": 2
|
|
|
+// };
|
|
|
+
|
|
|
+// for (let i = 0; i < tokens.length; i++) {
|
|
|
+// const token = tokens[i];
|
|
|
+
|
|
|
+// // 检查连续运算符
|
|
|
+// if (i > 0 && this.isOperator(token) && this.isOperator(tokens[i - 1])) {
|
|
|
+// this.showWarning("公式错误");
|
|
|
+// return []; // 返回空数组表示错误
|
|
|
+// }
|
|
|
+
|
|
|
+// if (!isNaN(Number(token))) {
|
|
|
+// output.push(new Decimal(token));
|
|
|
+// } else if (token === "(") {
|
|
|
+// operators.push(token);
|
|
|
+// } else if (token === ")") {
|
|
|
+// while (operators.length && operators[operators.length - 1] !== "(") {
|
|
|
+// output.push(operators.pop()!);
|
|
|
+// }
|
|
|
+// operators.pop(); // 弹出 '('
|
|
|
+// } else {
|
|
|
+// while (
|
|
|
+// operators.length &&
|
|
|
+// precedence[operators[operators.length - 1]] >= precedence[token]
|
|
|
+// ) {
|
|
|
+// output.push(operators.pop()!);
|
|
|
+// }
|
|
|
+// operators.push(token);
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// while (operators.length) {
|
|
|
+// output.push(operators.pop()!);
|
|
|
+// }
|
|
|
+
|
|
|
+// return output;
|
|
|
+// }
|
|
|
+
|
|
|
+// // 判断是否为运算符
|
|
|
+// private isOperator(token: string): boolean {
|
|
|
+// return ["+", "-", "*", "/"].includes(token);
|
|
|
+// }
|
|
|
+
|
|
|
+// private showWarning(message: string): void {
|
|
|
+// ElMessage({
|
|
|
+// message: message,
|
|
|
+// type: "warning"
|
|
|
+// });
|
|
|
+// }
|
|
|
+
|
|
|
+// // 计算解析后的表达式
|
|
|
+// private evaluate(parsedExpression: Array<Decimal | string>): number {
|
|
|
+// const stack: Array<Decimal> = [];
|
|
|
+
|
|
|
+// for (const token of parsedExpression) {
|
|
|
+// if (token instanceof Decimal) {
|
|
|
+// stack.push(token);
|
|
|
+// } else {
|
|
|
+// const b = stack.pop()!;
|
|
|
+// const a = stack.pop()!;
|
|
|
+// switch (token) {
|
|
|
+// case "+":
|
|
|
+// stack.push(a.plus(b));
|
|
|
+// break;
|
|
|
+// case "-":
|
|
|
+// stack.push(a.minus(b));
|
|
|
+// break;
|
|
|
+// case "*":
|
|
|
+// stack.push(a.times(b));
|
|
|
+// break;
|
|
|
+// case "/":
|
|
|
+// if (b.isZero()) {
|
|
|
+// this.showWarning("除数不能为零");
|
|
|
+// throw new Error("除数不能为零");
|
|
|
+// }
|
|
|
+// stack.push(a.dividedBy(b));
|
|
|
+// break;
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// return stack[0].toNumber(); // 返回计算结果
|
|
|
+// }
|
|
|
+// }
|
|
|
class Counter {
|
|
|
+ private result: Decimal;
|
|
|
+
|
|
|
constructor() {
|
|
|
- this.result = 0;
|
|
|
+ this.result = new Decimal(0);
|
|
|
}
|
|
|
|
|
|
// 加法
|
|
|
- addition(val) {
|
|
|
- this.result += val;
|
|
|
+ addition(val: number | string): this {
|
|
|
+ this.result = this.result.plus(new Decimal(val));
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
// 减法
|
|
|
- subtraction(val) {
|
|
|
- this.result -= val;
|
|
|
+ subtraction(val: number | string): this {
|
|
|
+ this.result = this.result.minus(new Decimal(val));
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
// 乘法
|
|
|
- multiplication(val) {
|
|
|
- this.result *= val;
|
|
|
+ multiplication(val: number | string): this {
|
|
|
+ this.result = this.result.times(new Decimal(val));
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
// 除法
|
|
|
- division(val) {
|
|
|
- this.result /= val;
|
|
|
+ division(val: number | string): this {
|
|
|
+ if (new Decimal(val).isZero()) {
|
|
|
+ throw new Error("除数不能为零");
|
|
|
+ }
|
|
|
+ this.result = this.result.dividedBy(new Decimal(val));
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
// 计算表达式
|
|
|
- calculate(expression) {
|
|
|
+ calculate(expression: string): this {
|
|
|
const tokens = this.tokenize(expression);
|
|
|
const parsedExpression = this.parse(tokens);
|
|
|
- this.result = this.evaluate(parsedExpression);
|
|
|
+ this.result = new Decimal(this.evaluate(parsedExpression));
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
// 获取结果
|
|
|
- get() {
|
|
|
- return this.result;
|
|
|
+ get(): number {
|
|
|
+ return this.result.toNumber(); // 返回普通数字
|
|
|
}
|
|
|
|
|
|
// 词法分析,将字符串分割为token
|
|
|
- tokenize(expression) {
|
|
|
- return expression.match(/(\d+(\.\d+)?|[-+*/()])/g);
|
|
|
+ private tokenize(expression: string): Array<string> {
|
|
|
+ // 使用正则表达式来允许负数
|
|
|
+ return expression.match(/-?\d+(\.\d+)?|[-+*/()]/g) || [];
|
|
|
}
|
|
|
|
|
|
// 解析表达式
|
|
|
- parse(tokens) {
|
|
|
- const output = [];
|
|
|
- const operators = [];
|
|
|
- const precedence = {
|
|
|
+ private parse(tokens: Array<string>): Array<Decimal | string> {
|
|
|
+ const output: Array<Decimal | string> = [];
|
|
|
+ const operators: Array<string> = [];
|
|
|
+ const precedence: { [key: string]: number } = {
|
|
|
"+": 1,
|
|
|
"-": 1,
|
|
|
"*": 2,
|
|
|
"/": 2
|
|
|
};
|
|
|
|
|
|
- for (const token of tokens) {
|
|
|
- if (!isNaN(token)) {
|
|
|
- output.push(Number(token));
|
|
|
+ for (let i = 0; i < tokens.length; i++) {
|
|
|
+ const token = tokens[i];
|
|
|
+
|
|
|
+ // 检查连续运算符
|
|
|
+ if (i > 0 && this.isOperator(token) && this.isOperator(tokens[i - 1])) {
|
|
|
+ this.showWarning("公式错误");
|
|
|
+ return []; // 返回空数组表示错误
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!isNaN(Number(token))) {
|
|
|
+ output.push(new Decimal(token));
|
|
|
} else if (token === "(") {
|
|
|
operators.push(token);
|
|
|
} else if (token === ")") {
|
|
|
while (operators.length && operators[operators.length - 1] !== "(") {
|
|
|
- output.push(operators.pop());
|
|
|
+ output.push(operators.pop()!);
|
|
|
}
|
|
|
operators.pop(); // 弹出 '('
|
|
|
} else {
|
|
@@ -71,50 +233,67 @@ class Counter {
|
|
|
operators.length &&
|
|
|
precedence[operators[operators.length - 1]] >= precedence[token]
|
|
|
) {
|
|
|
- output.push(operators.pop());
|
|
|
+ output.push(operators.pop()!);
|
|
|
}
|
|
|
operators.push(token);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
while (operators.length) {
|
|
|
- output.push(operators.pop());
|
|
|
+ output.push(operators.pop()!);
|
|
|
}
|
|
|
|
|
|
return output;
|
|
|
}
|
|
|
|
|
|
+ // 判断是否为运算符
|
|
|
+ private isOperator(token: string): boolean {
|
|
|
+ return ["+", "-", "*", "/"].includes(token);
|
|
|
+ }
|
|
|
+
|
|
|
+ private showWarning(message: string): void {
|
|
|
+ // 假设 ElMessage 是某个库的消息提示函数
|
|
|
+ // 假设 ElMessage 是某个库的消息提示函数
|
|
|
+ ElMessage({
|
|
|
+ message: message,
|
|
|
+ type: "warning"
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
// 计算解析后的表达式
|
|
|
- evaluate(parsedExpression) {
|
|
|
- const stack = [];
|
|
|
+ private evaluate(parsedExpression: Array<Decimal | string>): number {
|
|
|
+ const stack: Array<Decimal> = [];
|
|
|
|
|
|
for (const token of parsedExpression) {
|
|
|
- if (typeof token === "number") {
|
|
|
+ if (token instanceof Decimal) {
|
|
|
stack.push(token);
|
|
|
} else {
|
|
|
- const b = stack.pop();
|
|
|
- const a = stack.pop();
|
|
|
+ const b = stack.pop()!;
|
|
|
+ const a = stack.pop()!;
|
|
|
switch (token) {
|
|
|
case "+":
|
|
|
- stack.push(a + b);
|
|
|
+ stack.push(a.plus(b));
|
|
|
break;
|
|
|
case "-":
|
|
|
- stack.push(a - b);
|
|
|
+ stack.push(a.minus(b));
|
|
|
break;
|
|
|
case "*":
|
|
|
- stack.push(a * b);
|
|
|
+ stack.push(a.times(b));
|
|
|
break;
|
|
|
case "/":
|
|
|
- stack.push(a / b);
|
|
|
+ if (b.isZero()) {
|
|
|
+ this.showWarning("除数不能为零");
|
|
|
+ throw new Error("除数不能为零");
|
|
|
+ }
|
|
|
+ stack.push(a.dividedBy(b));
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return stack[0];
|
|
|
+ return stack[0].toNumber(); // 返回计算结果
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
// 使用示例
|
|
|
// const calculator = new Counter();
|
|
|
// calculator.calculate("3.5 + 2.3 * (2 - 8)");
|