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

时间:2019-03-20 19:56:55

标签: python

我正在尝试创建一个将方程式作为输入并基于运算进行求值的函数,规则是我应该在运算符之间(*,+,-,%,^) 正确的数学表达式,例如:

Int

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

Input: 6**8 
Result: Not correct

原因:“-”在开头,并且不在两个数字之间。

Input: -6+2
Result: Not correct

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

旁边

7 个答案:

答案 0 :(得分:1)

1。选项:eval

eval带有try-except的表达式:

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

优势:

  • 非常轻松快捷

缺点:

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

2。选项:算法

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

这是您可以做的非常简短的结构:

  • 解析中缀表达式
  • 将中缀表达式转换为后缀表达式
  • 计算后缀表达式

您需要了解后缀和中缀表达式的含义。

资源:

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

反向抛光符号/后修复符号:https://en.wikipedia.org/wiki/Reverse_Polish_notation

Python内置令牌生成器:https://docs.python.org/3.7/library/tokenize.html

优势:

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

缺点

  • 难以理解
  • 实施复杂

答案 1 :(得分:1)

如评论中所述,这称为parsing,并且需要语法。
查看带有PEG解析器parsimonious的示例:

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))

这产生

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.

答案 2 :(得分:0)

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

认为您可以使用的最佳算法是RPN(反向波兰表示法)。

答案 3 :(得分:0)

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

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

# prints "6 * 2 + 3"

答案 4 :(得分:0)

似乎您可能刚刚开始使用python。总有很多方法可以解决问题。一种让您快速入门的有趣方法是考虑根据运算符拆分方程式。

例如,以下代码使用正则表达式拆分公式:

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'\*|\/|\%|\^|\+|\-'片断中,\表示从字面上接受下一个字符,而|则表示|。表示“或”,因此它会评估将其中一个运算符拆分。

在这种情况下,您会发现,任何时候同时存在两个运算符,或者公式以一个运算符开头时,您的列表中将有一个空白值-第二个为一个-第一个公式为一个领先-在第二个公式中。

基于此,您可以说:

if '' in re.split(r'\*|\/|\%|\^|\+|\-',formula):
     correctsign = False

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

答案 5 :(得分:0)

首先要提到**代表幂,即6**8:6等于8的幂。

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

您也可以使用elif代替嵌套的else语句来获得更简洁的代码。

在不更改核心算法的情况下,您的代码将如下所示:

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"

答案 6 :(得分:0)

您可以使用Python的ast模块来解析表达式:

public class StockConfiguration : IEntityTypeConfiguration<Stock>
    {
        public void Configure(EntityTypeBuilder<Stock> builder)
        {
            builder
                .ToTable("Stocks");

            builder
                .Property<int>("StockID")
                .HasColumnType("int")
                .ValueGeneratedOnAdd()
                .HasAnnotation("Key", 0);

            builder
                .Property(stock => stock.Name)
                .HasColumnName("Name")
                .HasMaxLength(25)
                .IsRequired();

            builder
                .HasMany(stock => stock.Transactions)
                .WithOne(transaction => transaction.RelatedStock)
                .IsRequired();

            builder
                .HasIndex(stock => stock.Name)
                .IsUnique();
        }
    }

第一种情况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