Python-试图创建一个“自由手”计算器

时间:2013-05-09 00:21:11

标签: python int calculator equation

我正在尝试创建一个计算器程序,用户可以在其中键入方程式并获得答案。我不想要完整的代码,我只需要特定部分的帮助。

我想要的方法是让用户输入方程式作为字符串(raw_input)然后我尝试将数字从输入转换为整数。之后,我需要知道如何让操作数完成我希望他们做的操作,具体取决于用户使用哪个操作数以及它在等式中的位置。

我可以用什么方法来完成这项任务?

这基本上就是我现在所拥有的:

    equation_number = raw_input("\nEnter your equation now: ")
    [int(d) for d in equation_number if d.isdigit()]

这些行仅用于收集输入并尝试将数字转换为整数。不幸的是,它似乎并没有很好地工作,而且.isdigit无论如何只适用于正数。

Edit- aong152提到了递归解析,我调查了它,看起来有理想的结果:

http://blog.erezsh.com/how-to-write-a-calculator-in-70-python-lines-by-writing-a-recursive-descent-parser/

但是,我不明白这篇文章的作者正在使用的代码,是否有人可以让我熟悉递归解析的基础知识?

4 个答案:

答案 0 :(得分:1)

您尝试制作的节目类型可能比您想象的更复杂

第一步是将字符串分成每个参数。

假设用户输入:

1 + 2.0 + 3 + 4

在转换为整数之前,您需要将字符串拆分为其组件:

  • 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/ 至少开始应该很容易。需要注意的事项:

  • 语法结构如何产生优先级 - addmul组成,反之亦然。

  • 他为括号添加规则的那一刻:

    atom: neg | number | '(' add ')';
    

    这是它真正变得递归的地方!

  • 6-2-1应解析为(6-2)-1,而不是6-(2-1)。他不讨论它,但如果你看 仔细地,它也来自语法的结构。不要在此浪费时间;只知道将来会被称为 associativity

  • 解析的结果是。然后,您可以自下而上的方式计算其值。 在“计算!”他这样做的章节,但是以一种神奇的方式。 不要担心。


要自己构建一个计算器,我建议你尽可能地解决问题。

  1. 认识到数字结束等等有点混乱。它可以是语法的一部分,也可以通过名为 lexer tokenizer 的单独传递来完成。
    我建议你跳过它 - 要求用户在所有操作员和parens周围输入空格。或者假设您已经获得了[2.0, "*", "(", 3.0, "+", -1.0, ")"]形式的列表。

  2. 从一个简单的解析器(令牌)函数开始,该函数只处理3个元素的表达式 - [number,op,number]。 返回单个数字,计算结果。 (我之前说解析器会输出一个稍后会处理的树。不要担心,返回一个数字会更简单。)

  3. 编写一个需要数字或括号的函数 - 在后一种情况下,它会调用parser()。

    >>> number_or_expr([1.0, "rest..."])
    (1.0, ["rest..."])
    >>> number_or_expr(["(", 2.0, "+", 2.0, ")", "rest..."])
    (4.0, ["rest..."])
    

    请注意,我现在正在返回第二个值 - 输入的剩余部分。更改解析器()也使用此约定。

  4. 现在重写parser()来调用number_or_expr()而不是直接假设tokens [0]和tokens [2]是数字。
    中提琴!你现在有一个(相互)递归计算器可以计算任何东西 - 它只需要用冗长的样式编写,并且包含所有内容。

  5. 现在停下来欣赏你的代码,至少一天:-)它仍然很简单,但具有解析的基本递归性质。代码结构反映了语法1:1(这是递归下降的好属性。你不想知道其他算法的外观)。

    从这里可以进行许多改进 - 支持2 + 2 + 2,允许(1),优先...... - 但有两种方法可以解决这个问题:

    • 逐步改进您的代码。你必须经常重构。
    • 停止努力并使用解析库,例如pyparsing。 这将允许您更快地试验语法更改。