我试图创建一个函数,将一个方程作为输入并根据操作进行评估,规则是我应该在正确的数学表达式之间有运算符(*,+, - ,%,^),例如:
Input: 6**8
Result: Not correct
原因:*旁边有另一个*而不是数字或数学表达式
Input: -6+2
Result: Not correct
原因:“ - ”在开始时并没有介于两个数字之间。
Input: 6*(2+3)
Result: Correct
原因:“*”旁边是数学上正确的表达式“(2 + 3)
eval
表达式try-except:
try:
result = eval(expression)
correct_sign = True
except SyntaxError:
correct_sign = False
好处:
缺点:
在编译器中使用算法,以使pc的数学表达式可读。这些算法也可用于评估表达式是否有效。我不打算解释这些算法。外面有足够的资源。
这是一个非常简短的结构,你可以做什么:
您需要了解postfix和infix表达式的含义。
资源:
调车场算法:https://en.wikipedia.org/wiki/Shunting-yard_algorithm
反向抛光符号/后缀符号:qazxsw poi
Python内置标记器:https://en.wikipedia.org/wiki/Reverse_Polish_notation
好处:
缺点
如评论中所述,这称为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))
您需要使用正确的数据结构和算法来实现解析数学方程式并对其进行评估的目标。您还必须熟悉两个概念:用于创建解析器的堆栈和树。
认为你可以使用的最佳算法是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.
(反向波兰表示法)。
对于问题#1,您可以在评估之前始终去掉括号。
RPN
看起来你可能刚刚开始使用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'\*|\/|\%|\^|\+|\-'
也许这可以作为让大脑思考解决问题的有趣方法的良好起点。
重要的是首先提到if '' in re.split(r'\*|\/|\%|\^|\+|\-',formula):
correctsign = False
代表取幂,即**
:6代表8的幂。
算法背后的逻辑是错误的,因为在您的代码中,响应仅取决于最后一个数字/符号是否满足您的条件。这是因为一旦循环完成,你的布尔值6**8
默认为基于最后一个数字/符号的correctsigns
或True
。
你也可以使用False
而不是嵌套的elif
语句来获得更干净的代码。
在不更改核心算法的情况下,您的代码会像这样:
else
您可以使用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
。