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不安全
- 解析中缀表达式
- 将中缀表达式转换为后缀表达式
- 计算后缀表达式
- 可靠的
- 适用于复杂表达式
- 你不必重新发明轮子
- 难懂
- 实施复杂化
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我认为问题是,负号“-”不在两个表达式之间