本人是一名六年级在校学生,对程序有较浅研究,长期活跃于github及学而思社区
本作品将同步发布于共创社区(浅梦·星迹)-浅梦·星迹的主页
学而思社区(浅梦)-浅梦的主页
望支持!
为了方便理解,我截取了一段百度上的解释(如下图)
表达式,是由数字、算符、数字分组符号(括号)、自由变量和约束变量等以能求得数值的有意义排列方法所得的组合。约束变量在表达式中已被指定数值,而自由变量则可以在表达式之外另行指定数值。
意义给予自由变量一些数值指定,可以给与一个表达式数值,即使对于一些自由变量的值,表示式或许没有定义。因此,一个表达式代表一个函数,其输入为自由变量的定值,而其输出则为表示式因之后所产生出的数值。
很玄乎,但是通俗易懂的讲就是一个式子,而我们的目标就是让计算机读懂式子并计算。
首先的思路使用exec,但这也未免太简单了,于是我们默认计算机只能计算没有优先级制度的基础运算,如a+b,a-b,a*b,a/b,a%b等等,有了思路,我们应该如何实现?
我有我的个人思路,那么我们现看看百度上是如何实现的(原文链接鱼翔浅底的作品)
INTEGER, PLUS, MINUS, MUL, DIV, LPAREN, RPAREN, EOF = 'INTEGER', 'PLUS', 'MINUS', 'MUL', 'DIV', 'LPAREN', 'RPAREN',\
'EOF '
# 整数,加法,减法,乘法、除法,左括号,右括号,结束标识
class Token:
def __init__(self, type, value):
self.tp = type
self.value = value
def __str__(self):
return 'Token({type},{value})'.format(type=self.tp, value=self.value)
def __repr__(self):
return self.__str__()
class Lexer:
def __init__(self, text):
self.text = text
self.position = 0
self.current_char = self.text[self.position]
def error(self):
raise Exception('错误的输入内容!')
def advance(self):
self.position += 1
if self.position >= len(self.text):
self.current_char = None
else:
self.current_char = self.text[self.position]
def skip_whitespace(self):
while self.current_char is not None and self.current_char.isspace():
self.advance()
def integer(self):
result = ''
while self.current_char is not None and self.current_char.isdigit():
result += self.current_char
self.advance()
return int(result)
def get_next_token(self):
while self.current_char is not None:
if self.current_char.isspace():
self.skip_whitespace()
continue
if self.current_char.isdigit():
return Token(INTEGER, self.integer())
if self.current_char == '+':
self.advance()
return Token(PLUS, '+')
if self.current_char == '-':
self.advance()
return Token(MINUS, '-')
if self.current_char == '*':
self.advance()
return Token(MUL, '*')
if self.current_char == '/':
self.advance()
return Token(DIV, '/')
if self.current_char == '(':
self.advance()
return Token(LPAREN, '(')
if self.current_char == ')':
self.advance()
return Token(RPAREN, ')')
self.error()
return Token(EOF, None)
class AST(object):
pass
class BinOp(AST):
def __init__(self, left, op, right):
self.left = left
self.token = self.op = op
self.right = right
class Num(AST):
def __init__(self, token):
self.token = token
self.value = token.value
class Parser: # 语法分析器
def __init__(self, lexer):
self.lexer = lexer
self.current_token = self.lexer.get_next_token()
def eat(self, token_type):
if self.current_token.tp == token_type:
self.current_token = self.lexer.get_next_token()
else:
self.lexer.error()
def factor(self):
token = self.current_token
if token.tp == INTEGER:
self.eat(INTEGER)
return Num(token)
elif token.tp == LPAREN:
self.eat(LPAREN)
node = self.expr()
self.eat(RPAREN)
return node
def term(self):
node = self.factor()
while self.current_token.tp in (MUL, DIV):
token = self.current_token
if token.tp == MUL:
self.eat(MUL)
if token.tp == DIV:
self.eat(DIV)
node = BinOp(left=node, op=token, right=self.factor())
return node
def expr(self):
node = self.term()
while self.current_token.tp in (PLUS, MINUS):
token = self.current_token
if token.tp == PLUS:
self.eat(PLUS)
if token.tp == MINUS:
self.eat(MINUS)
node = BinOp(left=node, op=token, right=self.term())
return node
def parse(self):
return self.expr()
class NodeVisitor(object):
def visit(self, node):
method_name = 'visit_' + type(node).__name__
visitor = getattr(self, method_name, self.generic_visit)
return visitor(node)
def generic_visit(self, node):
raise Exception('No visit_{} method'.format(type(node).__name__))
class Interpreter(NodeVisitor):
def __init__(self, parser):
self.parser = parser
def visit_BinOp(self, node):
if node.op.tp == PLUS:
return self.visit(node.left) + self.visit(node.right)
elif node.op.tp == MINUS:
return self.visit(node.left) - self.visit(node.right)
elif node.op.tp == MUL:
return self.visit(node.left) * self.visit(node.right)
elif node.op.tp == DIV:
return self.visit(node.left) // self.visit(node.right)
def visit_Num(self, node):
return node.value
def interpret(self):
tree = self.parser.parse()
return self.visit(tree)
def main():
while True:
try:
text = input('Expression>>>')
except EOFError:
break
if not text:
continue
lexer = Lexer(text)
parser = Parser(lexer)
interpreter = Interpreter(parser)
result = interpreter.interpret()
print(text, '=', result)
_token = Token()if __name__ == '__main__':
main()
那我来讲讲我的算法
首先要将整个表达式分层,也就是split分等于号
ch = ch.split("=")
接着寻找其中的运算符和数值,并按照优先级对每一个数值和符号组定义一个优先值(我用了三个二位列表,不习惯用字典)
这里我就不作展示,写一个token类即可,很方便
最后依次按照优先级计算即可,这样简单的表达式就写完了。
这里我展示以下没有写完优先级的源代码
class Token:
def __init__(self):
self._count = ["+","-","*","/"] #所有运算符
self._count1,self._count2 = [],[] #所有运算符和索引
self.number = [] #所有数字
self.code = "" #去空格后代码
self.over = 0 #返回值
def count(self,code): #计算方法
self._count1,self._count2 = [],[]
self.number = []
self.code = ""
self.over = 0
for i in code: #去空格
if i != " ":self.code += i
for i in range(len(self.code)): #寻找运算符
if self.code[i] in self._count:
self._count1.append(self.code[i])
self._count2.append(i)
#以下开始寻找所有参与计算的数字,第一个和最后一个特殊处理
self.number.append(self.code[0:self._count2[0]])
for i in range(len(self._count2)):
self.number.append(self.code[self._count2[i-1]+1:self._count2[i]])
del self.number[1]
self.number.append(self.code[self._count2[len(self._count2)-1]:len(self.code)])
var = self.number[len(self.number)-1]
del self.number[len(self.number)-1]
self.number.append(var[1:len(var)])
self.over = int(self.number[0])
#开始计算
for i in range(len(self._count2)):
if self._count1[i] == "+":self.over = self.over + int(self.number[i+1])
if self._count1[i] == "-":self.over = self.over - int(self.number[i+1])
if self._count1[i] == "*":self.over = self.over * int(self.number[i+1])
if self._count1[i] == "/":self.over = self.over / int(self.number[i+1])
return self.over
写的比较简陋,很多地方没来得及改用了特殊处理,缩减完后代码会更少
~本次文章写完,记得点赞关注投币~