浅谈Python之表达式怎么写?

零.写在前面

本人是一名六年级在校学生,对程序有较浅研究,长期活跃于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

写的比较简陋,很多地方没来得及改用了特殊处理,缩减完后代码会更少


~本次文章写完,记得点赞关注投币~

你可能感兴趣的:(python,git,算法)