Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/356.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何检查等式中运算符的顺序是否正确?_Python - Fatal编程技术网

Python 如何检查等式中运算符的顺序是否正确?

Python 如何检查等式中运算符的顺序是否正确?,python,Python,我试图创建一个函数,将一个方程作为输入,并根据运算对其进行求值,规则是在正确的数学表达式之间应该有运算符(*,+,-,%,^),例如: Input: 6**8 Result: Not correct 原因:*旁边有另一个*而不是数字或数学表达式 Input: -6+2 Result: Not correct 原因:“-”在开头,不在两个数字之间 Input: 6*(2+3) Result: Correct 原因:“*”位于数学上正确的表达式旁边”(2+3)您需要使用正确的数据结构和算法来

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

Input: 6**8 
Result: Not correct
原因:*旁边有另一个*而不是数字或数学表达式

Input: -6+2
Result: Not correct
原因:“-”在开头,不在两个数字之间

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

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

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

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

对于问题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"

看起来你可能只是开始使用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

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

首先要提到的是,
**
代表指数运算,即
6**8
:6乘以8的幂

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

您还可以使用
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"
1.选项:评估
eval
使用try-except的表达式:

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

  • 非常简单和快速
缺点:

  • Python接受您可能不想要的表达式(例如,.*在Python中有效)
  • eval不安全
2.选项:算法 在编译器中,算法用于使数学表达式对pc机可读。这些算法还可用于评估表达式是否有效。 我不打算解释这些算法。外部有足够的资源

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

  • 解析中缀表达式
  • 将中缀表达式转换为后缀表达式
  • 计算后缀表达式
您需要理解后缀和中缀表达式的含义

资源:

调车场算法:

反向波兰符号/后修复符号:

Python内置标记器:

优点:

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

  • 难懂
  • 实施复杂化
您可以使用Python模块解析表达式:

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
对应于
ast.UnaryOp

,如注释中所述,这称为
解析
,需要语法。
请参见带有
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))
这就产生了

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.

您正在显式检查*左右的项是否为数字,而不是数字。这称为“解析”“。一种方法是为数学表达式创建语法,然后为该语法编写解析器。一种有用的算法可能是分流场算法:
-6+2
-4
,对我来说似乎是一个非常正确的结果…@Jan我认为问题是,负号“-”不在两个表达式之间