如何检查方程中运算符的顺序是否正确?

问题描述 投票:4回答:7

我试图创建一个函数,将一个方程作为输入并根据操作进行评估,规则是我应该在正确的数学表达式之间有运算符(*,+, - ,%,^),例如:

Input: 6**8 
Result: Not correct

原因:*旁边有另一个*而不是数字或数学表达式

Input: -6+2
Result: Not correct

原因:“ - ”在开始时并没有介于两个数字之间。

Input: 6*(2+3)
Result: Correct

原因:“*”旁边是数学上正确的表达式“(2 + 3)

python
7个回答
1
投票

1.选项:评估

eval表达式try-except:

try:
    result = eval(expression)
    correct_sign = True
except SyntaxError:
    correct_sign = False

好处:

  • 非常简单快捷

缺点:

  • Python接受你可能不想要的表达式(例如**在python中有效)
  • 评估不安全

2.选项:算法

在编译器中使用算法,以使pc的数学表达式可读。这些算法也可用于评估表达式是否有效。我不打算解释这些算法。外面有足够的资源。

这是一个非常简短的结构,你可以做什么:

  • 解析中缀表达式
  • 将中缀表达式转换为后缀表达式
  • 评估后缀表达式

您需要了解postfix和infix表达式的含义。

资源:

调车场算法:https://en.wikipedia.org/wiki/Shunting-yard_algorithm

反向抛光符号/后缀符号:qazxsw poi

Python内置标记器:https://en.wikipedia.org/wiki/Reverse_Polish_notation

好处:

  • 可靠
  • 适用于复杂的表达式
  • 你不必重新发明轮子

缺点

  • 很难理解
  • 实施起来很复杂

1
投票

如评论中所述,这称为https://docs.python.org/3.7/library/tokenize.html并需要语法。 查看parsing的示例,parsimonious解析器:

PEG

这产生了

from parsimonious.grammar import Grammar
from parsimonious.nodes import NodeVisitor
from parsimonious.exceptions import ParseError

grammar = Grammar(
    r"""
    expr        = (term operator term)+
    term        = (lpar factor rpar) / number
    factor      = (number operator number)

    operator    = ws? (mod / mult / sub / add) ws?
    add         = "+"
    sub         = "-"
    mult        = "*"
    mod         = "/"

    number      = ~"\d+(?:\.\d+)?"
    lpar        = ws? "(" ws?
    rpar        = ws? ")" ws?
    ws          = ~"\s+"
    """
)


class SimpleCalculator(NodeVisitor):

    def generic_visit(self, node, children):
        return children or node

    def visit_expr(self, node, children):
        return self.calc(children[0])

    def visit_operator(self, node, children):
        _, operator, *_ = node
        return operator

    def visit_term(self, node, children):
        child = children[0]
        if isinstance(child, list):
            _, factor, *_ = child
            return factor
        else:
            return child

    def visit_factor(self, node, children):
        return self.calc(children)

    def calc(self, params):
        """ Calculates the actual equation. """
        x, op, y = params
        op = op.text

        if not isinstance(x, float):
            x = float(x.text)
        if not isinstance(y, float):
            y = float(y.text)

        if op == "+":
            return x+y
        elif op == "-":
            return x-y
        elif op == "/":
            return x/y
        elif op == "*":
            return x*y

equations = ["6 *(2+3)", "2+2", "4*8", "123-23", "-1+1", "100/10", "6**6"]

c = SimpleCalculator()
for equation in equations:
    try:
        tree = grammar.parse(equation)
        result = c.visit(tree)
        print("{} = {}".format(equation, result))
    except ParseError:
        print("The equation {} could not be parsed.".format(equation))

0
投票

您需要使用正确的数据结构和算法来实现解析数学方程式并对其进行评估的目标。您还必须熟悉两个概念:用于创建解析器的堆栈和树。

认为你可以使用的最佳算法是6 *(2+3) = 30.0 2+2 = 4.0 4*8 = 32.0 123-23 = 100.0 The equation -1+1 could not be parsed. 100/10 = 10.0 The equation 6**6 could not be parsed. (反向波兰表示法)。


0
投票

对于问题#1,您可以在评估之前始终去掉括号。

RPN

0
投票

看起来你可能刚刚开始使用python。总有很多方法可以解决问题。让你跳起来的一个有趣的方法是考虑根据运算符分割方程。

例如,以下使用所谓的正则表达式来拆分公式:

input_string = "6*(2+3)"
it = filter(lambda x: x != '(' and x != ')', input_string)
after = ' '.join(list(it))
print(after)

# prints "6 * 2 + 3"

它可能看起来很复杂,但在import re >>> formula2 = '6+3+5--5' >>> re.split(r'\*|\/|\%|\^|\+|\-',formula2) ['6', '3', '5', '', '5'] >>> formula3 = '-2+5' >>> re.split(r'\*|\/|\%|\^|\+|\-',formula3) ['', '2', '5'] 片中,\意味着从字面上理解下一个字符和|表示'或',因此它评估拆分任何一个运算符。

在这种情况下,您会注意到任何时候有两个操作符在一起,或者当一个公式以一个操作符开头时,您的列表中将有一个空白值 - 第二个中的一个 - 在第一个公式中,一个用于前导 - 第二个公式。

基于此你可以说:

r'\*|\/|\%|\^|\+|\-'

也许这可以作为让大脑思考解决问题的有趣方法的良好起点。


0
投票

重要的是首先提到if '' in re.split(r'\*|\/|\%|\^|\+|\-',formula): correctsign = False 代表取幂,即**:6代表8的幂。

算法背后的逻辑是错误的,因为在您的代码中,响应仅取决于最后一个数字/符号是否满足您的条件。这是因为一旦循环完成,你的布尔值6**8默认为基于最后一个数字/符号的correctsignsTrue

你也可以使用False而不是嵌套的elif语句来获得更干净的代码。

在不更改核心算法的情况下,您的代码会像这样:

else

0
投票

您可以使用Python的def checksigns(equation): signs = ["*","/","%","^","+","-"] for i in signs: if i in equation: index = equation.index((i)) if (equation[index] == equation[0]): return "Not correct" elif (equation[index] == equation[len(equation) - 1]): return "Not correct" elif (equation[index + 1].isdigit() and equation[index - 1].isdigit()): return "Correct" else: return "Not correct" 模块来解析表达式:

ast

第一种情况import ast import itertools as it def check(expr): allowed = (ast.Add, ast.Sub, ast.Mult, ast.Mod) try: for node in it.islice(ast.walk(ast.parse(expr)), 2, None): if isinstance(node, (ast.BinOp, ast.Num)): continue if not isinstance(node, allowed): return False except SyntaxError: return False return True print(check('6**8')) # False print(check('-6+2')) # False print(check('6*(2+3)')) # True 评估为6**8,因为它由False节点和第二种情况表示,因为ast.Pow对应于-6

© www.soinside.com 2019 - 2024. All rights reserved.