给定一个字符串如:2/(3+4))*(3-1)+6-8 ,用程序解析出来,输出最终的值。这是个AST 语法解析问题,最直观的是建立一颗语法树,然后遍历语法树来获得最终的效果。如下图,建立这么一个语法树,然后广度优先搜索,进行操作就能得到最终的结果。
但是,其实我们有更方便的方法去做,不用建立语法树,而是利用栈,给每个操作符号定义优先级,就可以实现这个功能。一共的操作符号有:
( ) + - * /
只有这四种,定义其优先等级分别为:
( : -1
) : 0
+ : 1
- : 1
* : 2
/ : 2
解析表达式字符串,从左到右把它的字符加入到栈,如果遇到第二个操作符开始,其优先级小于前面的操作符的优先级,则先合并前面的操作符号的操作项,不断得重复此过程直到栈中只有一个符号。
我的程序定义了两个栈,一个栈是存操作符的,一个栈是存数值的。挺多处理的细节不文字表示了,看下面的代码(python实现)
class NodeOpt: """ 操作符节点 """ def __init__(self, ch, precedence): self.ch = ch self.precedence = precedence class AST: """ 加减乘除任意组合的语法解析器 """ # 操作符栈 _operatorStack = [] # 值栈 _exprStack = [] # 具体操作符节点 left_range = NodeOpt(ch='(', precedence=-1) right_range = NodeOpt(ch=')', precedence=0) add = NodeOpt(ch='+', precedence=1) sub = NodeOpt(ch='-', precedence=1) mul = NodeOpt(ch='*', precedence=2) div = NodeOpt(ch='/', precedence=2) __opts = [add, sub, mul, div, left_range, right_range] def getOptNode(self, ch): """ 根据符号获取节点 """ for ops in self.__opts: if ops.ch == ch: return ops def isValue(self, ch): """ 判断是否为数值 """ if self.isOperator(ch): return False return True def isOperator(self, ch): """ 判断是否为操作符 """ for ops in self.__opts: if ops.ch == ch: return True return False def operator(self, e1, e2, operator): """ 执行操作 """ opt = operator.ch e1 = float(e1) e2 = float(e2) if opt is '+': return e1 + e2 elif opt is '-': return e1 - e2 elif opt is '*': return e1 * e2 elif opt is '/': return e1 / e2 else: return None def ifGo(self): if len(self._exprStack) >= 2 and len(self._operatorStack) >= 1: return True else: return False def parse(self, input): """ :param input: 字符数组 """ for ch in input: if ch is '(': ch = self.getOptNode(ch) self._operatorStack.append(ch) elif self.isValue(ch): self._exprStack.append(ch) elif self.isOperator(ch): ch = self.getOptNode(ch) while self.ifGo() and ch.precedence <= self._operatorStack[-1].precedence: e2 = self._exprStack.pop() e1 = self._exprStack.pop() operator = self._operatorStack.pop() self._exprStack.append(self.operator(e1, e2, operator)) self._operatorStack.append(ch) if ch.ch is ')': while self._operatorStack[-1].ch != '(': self._operatorStack.pop() self._operatorStack.pop() else: return Exception while self.ifGo(): e2 = self._exprStack.pop() e1 = self._exprStack.pop() operator = self._operatorStack.pop() self._exprStack.append(self.operator(e1, e2, operator)) return self._exprStack.pop() if __name__ == '__main__': ast = AST() myopt = "2/(3+((2-5)+1))*(3-1)+6-8" optlist = [] i = 0 while i < len(myopt): optlist.append(myopt[i]) i += 1 result = ast.parse(optlist) print(result)