我正在尝试创建一个计算器程序,用户可以在其中键入方程式并获得答案。我不想要完整的代码,我只需要特定部分的帮助。
我想要的方法是让用户输入方程式作为字符串(raw_input
)然后我尝试将数字从输入转换为整数。之后,我需要知道如何让操作数完成我希望他们做的操作,具体取决于用户使用哪个操作数以及它在等式中的位置。
我可以用什么方法来完成这项任务?
这基本上就是我现在所拥有的:
equation_number = raw_input("\nEnter your equation now: ")
[int(d) for d in equation_number if d.isdigit()]
这些行仅用于收集输入并尝试将数字转换为整数。不幸的是,它似乎并没有很好地工作,而且.isdigit无论如何只适用于正数。
Edit- aong152提到了递归解析,我调查了它,看起来有理想的结果:
但是,我不明白这篇文章的作者正在使用的代码,是否有人可以让我熟悉递归解析的基础知识?
答案 0 :(得分:1)
您尝试制作的节目类型可能比您想象的更复杂
第一步是将字符串分成每个参数。
假设用户输入:
1 + 2.0 + 3 + 4
在转换为整数之前,您需要将字符串拆分为其组件:
这将需要一个递归解析器,(看你是python的新手)可能有点障碍。
假设您现在将每个部分分别作为字符串,
float("2.0") = 2.0
int(2.0) = 2
这是辅助函数
def num (s):
try:
return int(s)
except exceptions.ValueError:
return int(float(s))
答案 1 :(得分:0)
而不是raw_input
只使用input
,因为raw_input
返回一个字符串而input
返回整数
这是一个非常简单的计算器:
def calculate():
x = input("Equation: ")
print x
while True:
calculate()
该函数接受input
并打印出来然后while循环再次执行
我不确定这是否是你想要的但是你去了,你也应该找到一个结束循环的方法
答案 2 :(得分:0)
使用raw_input()
后,您可以对结果使用eval()
来计算此字符串的值。 eval()
计算任何有效的Python表达式并返回结果。
但我认为这不符合你的喜好。你可能想自己做更多。
所以我认为你应该看一下re
模块,用正则表达式将输入分成标记(就像数字和运算符一样)。在此之后,您应该编写一个解析器,它将令牌流作为输入。你应该决定这个解析器是只返回计算值(例如一个数字)还是一个抽象语法树,i。即一种数据结构,它以面向对象(而不是面向字符)的方式表示表达式。然后可以评估这样的Absy以获得最终结果。
答案 3 :(得分:0)
你熟悉正则表达式吗?如果没有,首先了解它们可能是个好主意。它们是解析的弱,非递归表亲。不要深入,只要了解构建基块 - A然后B,A多次,A或B.
您发现的博客文章很难,因为它实现了手动解析。它使用递归下降,这是手动编写解析器并保持理智的唯一方法,但它仍然很棘手。
人们大多数时间所做的只是编写高级语法并使用库(或代码生成器)来完成解析的艰苦工作。 事实上,他有一个较早的帖子,他使用图书馆: http://blog.erezsh.com/how-to-write-a-calculator-in-50-python-lines-without-eval/ 至少开始应该很容易。需要注意的事项:
语法结构如何产生优先级 - add
由mul
组成,反之亦然。
他为括号添加规则的那一刻:
atom: neg | number | '(' add ')';
这是它真正变得递归的地方!
6-2-1
应解析为(6-2)-1,而不是6-(2-1)。他不讨论它,但如果你看
仔细地,它也来自语法的结构。不要在此浪费时间;只知道将来会被称为 associativity 。
解析的结果是树。然后,您可以自下而上的方式计算其值。 在“计算!”他这样做的章节,但是以一种神奇的方式。 不要担心。
要自己构建一个计算器,我建议你尽可能地解决问题。
认识到数字结束等等有点混乱。它可以是语法的一部分,也可以通过名为 lexer 或 tokenizer 的单独传递来完成。
我建议你跳过它 - 要求用户在所有操作员和parens周围输入空格。或者假设您已经获得了[2.0, "*", "(", 3.0, "+", -1.0, ")"]
形式的列表。
从一个简单的解析器(令牌)函数开始,该函数只处理3个元素的表达式 - [number,op,number]。 返回单个数字,计算结果。 (我之前说解析器会输出一个稍后会处理的树。不要担心,返回一个数字会更简单。)
编写一个需要数字或括号的函数 - 在后一种情况下,它会调用parser()。
>>> number_or_expr([1.0, "rest..."])
(1.0, ["rest..."])
>>> number_or_expr(["(", 2.0, "+", 2.0, ")", "rest..."])
(4.0, ["rest..."])
请注意,我现在正在返回第二个值 - 输入的剩余部分。更改解析器()也使用此约定。
现在重写parser()来调用number_or_expr()而不是直接假设tokens [0]和tokens [2]是数字。
中提琴!你现在有一个(相互)递归计算器可以计算任何东西 - 它只需要用冗长的样式编写,并且包含所有内容。
现在停下来欣赏你的代码,至少一天:-)它仍然很简单,但具有解析的基本递归性质。代码结构反映了语法1:1(这是递归下降的好属性。你不想知道其他算法的外观)。
从这里可以进行许多改进 - 支持2 + 2 + 2,允许(1),优先...... - 但有两种方法可以解决这个问题: