JS解析判断表达式(AST方式)

项目中需要解析表达式,如 ( A > ( B ) ) || (C != (D + E * F - 2) ) 。 公式存在一定规则: 为了确保公式的正确性,在生成公式中每一项时会使用括号进行包裹,如( A > ( B ) )(C != (D + E * F - 2) ), 同样内部比较符的右侧公式也会进行包裹如: ( B )(D + E * F - 2) 。 并且公式中条件全为||或者全为&&

第一想到的是抽象语法树(AST),使用到的类库:esprima,作用和使用方法不多做介绍,可以查阅官网。(体验网址:https://esprima.org/demo/parse.html#)
在这里插入图片描述
通过Tokens方式,将表达式从左向右解析为数组形式,事情就变得简单多了。

// 抽象语法树解析器
private esprima: Function;
...
ngOnInit() {
    
    
	// 引入esprima类库, (需要install)
	this.esprima = require('esprima');
}

private createSyntaxTree (expression: string) {
    
    
	// 先将表达式分解为每一项(因为条件全为 || 或者 &&  所以解析起来比较简单)
	// 根据||或者&&进行分割,不存在条件时,将自身存入数组
	let expressionList = (/\|\||&&/g).test(expression) ?
		(/\|\|/g).test(expression) ? expression.split('||') : expression.split('&&') :
		[expression];
	// 对每个公式项进行处理
	let compositionList = expressionList.map(item => {
    
    
		// 去除每个公式项两端括号 如( A > ( B ) ) 外层括号
		item = item.replace(/^\(|\)$/g, '');
		// 解析生成抽象语法树
		let AST = that.esprima.tokenize(item);
		// 获取表达式中所有的变量(type 为 Identifier)
		let variableList = AST.filter(_item => {
    
    
			return _item .type == "Identifier"
		});
		// 获取比较符  (type 为 Punctuator)
		let operator = AST.filter(item => {
    
    
			return item.type == "Punctuator"
		})[0].value;
		// 获取内部公式的组成如 C != (D + E * F - 2) 中的 (D + E * F - 2)
		let [, , ...innerFormulaComposition] = AST;
		// 将组成元素拼接为公式,并去除两端括号,即生成:D + E * F - 2
		let innerFormula = innerFormulaComposition.map(val => val.value)
			.join('').replace(/^\(|\)$/g, '');
		return {
    
    
			// 被比较的变量
			leftObj: variableList[0]
			operator: operator,
			innerFormula: innerFormula 
		}
	})
}

猜你喜欢

转载自blog.csdn.net/PGD_607/article/details/106589521
今日推荐