如何计算Typescript中的算术表达式?一个示例是'(3 + 5 *(-3 + -1))'。
Eval(...)被禁止。
运行时不接受建议的解决方案:
let input = '(3+5)';
let resultNumber = (new Function( 'return (' + input + ')'))();
错误是:
SyntaxError:无效或意外的令牌 在新功能()
对于我来说,具有136kb占用空间(压缩)的Math.js太大,无法评估简单表达式。可以通过限制功能进行自定义。
那么,您是否有一个小的打字稿文件/服务可以评估算术表达式?当然,一元减号/加号应该可以正常工作。
答案 0 :(得分:2)
由于@Mathyn,我发现了@Boann创建的一段不错的Java代码。我将其迁移到Typescript,就在那里。
下面还找到了Karma测试代码,因此可以看到可能的结果:+,-,(一元),*,^,/,花括号,(值),sin,cos,tan,sqrt等。
如何使用?在Angular中,您可以通过依赖注入来访问它。否则,您可以创建一个对象。您可以通过布尔值(此处为“ true”)进行指定,以将结果作为整数获取。
arithmeticExpressionEvaluator.evaluate('10 + 2 * 6') // shows 22.0
arithmeticExpressionEvaluator.evaluate('10 + 2 * 6', true) // shows 22 (integer only)
完整的Typescript源代码为:
export class ArithmeticExpressionEvaluator {
static INVALID_NUMBER = -1234567.654;
str: string;
pos = -1;
ch: string;
evaluate(expression: string): number {
return this.evaluateAll(expression, false);
}
evaluateAll(expression: string, resultIsInteger: boolean): number {
this.str = expression;
pos = -1;
const outcome = this.parse();
if (resultIsInteger) {
return Math.round(outcome);
}
return outcome;
}
nextChar() {
this.ch = (++this.pos < this.str.length) ? this.str.charAt(this.pos) : null;
}
eat(charToEat: string): boolean {
while (this.ch === ' ') {
this.nextChar();
}
if (this.ch === charToEat) {
this.nextChar();
return true;
}
return false;
}
parse(): number {
this.nextChar();
const x = this.parseExpression();
if (this.pos < this.str.length) {
return ArithmeticExpressionEvaluator.INVALID_NUMBER;
}
return x;
}
parseExpression(): number {
let x = this.parseTerm();
for (; ; ) {
if (this.eat('+')) { // addition
x += this.parseTerm();
} else if (this.eat('-')) { // subtraction
x -= this.parseTerm();
} else {
return x;
}
}
}
parseTerm(): number {
let x = this.parseFactor();
for (; ;) {
if (this.eat('*')) { // multiplication
x *= this.parseFactor();
} else if (this.eat('/')) { // division
x /= this.parseFactor();
} else {
return x;
}
}
}
parseFactor(): number {
if (this.eat('+')) { // unary plus
return this.parseFactor();
}
if (this.eat('-')) { // unary minus
return -this.parseFactor();
}
let x;
const startPos = this.pos;
if (this.eat('(')) { // parentheses
x = this.parseExpression();
this.eat(')');
} else if ((this.ch >= '0' && this.ch <= '9') || this.ch === '.') { // numbers
while ((this.ch >= '0' && this.ch <= '9') || this.ch === '.') {
this.nextChar();
}
x = parseFloat(this.str.substring(startPos, this.pos));
} else if (this.ch >= 'a' && this.ch <= 'z') { // functions
while (this.ch >= 'a' && this.ch <= 'z') {
this.nextChar();
}
const func = this.str.substring(startPos, this.pos);
x = this.parseFactor();
if (func === 'sqrt') {
x = Math.sqrt(x);
} else if (func === 'sin') {
x = Math.sin(this.degreesToRadians(x));
} else if (func === 'cos') {
x = Math.cos(this.degreesToRadians(x));
} else if (func === 'tan') {
x = Math.tan(this.degreesToRadians(x));
} else {
return ArithmeticExpressionEvaluator.INVALID_NUMBER;
}
} else {
return ArithmeticExpressionEvaluator.INVALID_NUMBER;
}
if (this.eat('^')) { // exponentiation
x = Math.pow(x, this.parseFactor());
}
return x;
}
degreesToRadians(degrees: number): number {
const pi = Math.PI;
return degrees * (pi / 180);
}
}
业力测试代码为:
import {ArithmeticExpressionEvaluator} from './arithmetic-expression-evaluator.service';
describe('Arithmetic Expression Evaluation', () => {
let arithmeticExpressionEvaluator: ArithmeticExpressionEvaluator;
beforeEach(() => {
arithmeticExpressionEvaluator = new ArithmeticExpressionEvaluator();
});
it('Arithmetic Expression Evaluation - double result', () => {
expect(arithmeticExpressionEvaluator.evaluate('10 + 2 * 6')).toBe(22.0);
expect(arithmeticExpressionEvaluator.evaluate('100 * 2 + 12')).toBe(212.0);
expect(arithmeticExpressionEvaluator.evaluate('100 * 2 + -12')).toBe(188.0);
expect(arithmeticExpressionEvaluator.evaluate('100 * (2) + -12')).toBe(188.0);
expect(arithmeticExpressionEvaluator.evaluate('-100 * 2 + 12')).toBe(-188.0);
expect(arithmeticExpressionEvaluator.evaluate('100 * 2 ^ 12')).toBe(409600.0);
expect(arithmeticExpressionEvaluator.evaluate('100 * ( 2 + 12 )')).toBe(1400.0);
expect(arithmeticExpressionEvaluator.evaluate('(100) * (( 2 ) + (12) )')).toBe(1400.0);
expect(arithmeticExpressionEvaluator.evaluate('100 * ( 2 + 12 ) / 14')).toBe(100.0);
});
it('Arithmetic Expression Evaluation - integer result', () => {
expect(arithmeticExpressionEvaluator.evaluateAll('10 + 2 * 6', true)).toBe(22);
expect(arithmeticExpressionEvaluator.evaluateAll('100 * 2 + 12' , true)).toBe(212);
expect(arithmeticExpressionEvaluator.evaluateAll('100 * 2 + -12', true)).toBe(188);
expect(arithmeticExpressionEvaluator.evaluateAll('100 * (2) + -12', true)).toBe(188);
expect(arithmeticExpressionEvaluator.evaluateAll('-100 * 2 + 12' , true)).toBe(-188);
expect(arithmeticExpressionEvaluator.evaluateAll('100 * 2 ^ 12', true)).toBe(409600);
expect(arithmeticExpressionEvaluator.evaluateAll('100 * ( 2 + 12 )', true)).toBe(1400);
expect(arithmeticExpressionEvaluator.evaluateAll('(100) * (( 2 ) + (12) )', true)).toBe(1400);
expect(arithmeticExpressionEvaluator.evaluateAll('100 * ( 2 + 12 ) / 14', true)).toBe(100);
});
});
答案 1 :(得分:0)
如果eval()
不在桌面上,则需要编写自定义DSL并编写自己的解析器。在某种程度上,您将构建eval()
已经为您完成的工作,但是可能是一个受限制的版本,没有所有的javascript功能。
或者找到现有的NPM软件包。