2013-05-09 3 views
0

Я пытаюсь создать программу калькулятора, в которой пользователь может ввести уравнение и получить ответ. Мне не нужен полный код для этого, мне просто нужна помощь с определенной частью.Python-stuck пытается создать калькулятор «свободной руки»

Подход, который я пытаюсь сделать, состоит в том, чтобы пользователь вводил уравнение в виде строки (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/

Однако, я не понимаю код, что автор этого поста использует, может ли кто-нибудь познакомить меня с основами рекурсивного синтаксического анализа?

+1

Первый совет: покажите, как вы ** в настоящее время пытаетесь ** получить эти данные и преобразовать их. Если вас еще нет, посмотрите, как получить вход пользователя и преобразовать строки в целые числа. – Jesse

+0

Под «уравнением» вы имеете в виду выражение для вычисления типа '6/2' или действительно уравнение для решения для x, например' 2 * x = 6'? –

ответ

0

вместо raw_input просто использовать input, потому что raw_input возвращает строку и input возвращает Интс

Это очень простой калькулятор:

def calculate(): 
    x = input("Equation: ") 
    print x 
while True: 
    calculate() 

функция принимает input и печатает его тогда исполняется, а цикл он снова

им не уверен, что это то, что вы хотите, но здесь вы идете, а также вы должны сделать способ закончить цикл

+3

'input' _evaluates_ строка. Это может быть проблематично, если кто-то захочет ввести что-то злонамеренное. например. Они могут стереть ваш жесткий диск, установить регистратор ключей и т. Д. –

0

После использования raw_input() вы можете использовать eval() на результат, чтобы вычислить значение этой строки. eval() оценивает любое допустимое выражение Python и возвращает результат.

Но я думаю, что это не по вашему вкусу. Возможно, вы захотите сделать больше самостоятельно.

Так что, я думаю, вы должны взглянуть на модуль re, чтобы разделить входные данные, используя регулярные выражения в токенах (sth как числа и операторы). После этого вы должны написать парсер, который получает поток токенов в качестве входных данных. Вы должны решить, должен ли этот парсер просто вернуть вычисленное значение (например, число) или, может быть, абстрактное синтаксическое дерево, т.е. е. структуру данных, которая представляет выражение в объектно-ориентированном (а не ориентированном на характер) пути. Такой Absy можно было бы оценить, чтобы получить окончательный результат.

1

Тип программы, которую вы пытаетесь сделать, вероятно, более сложным, чем вы думаете

Первым шагом будет разделение строки на каждый аргумент.

Давайте предположим, что пользователь вводит:

1 + 2,0 + 3 + 4

Перед тем, как можно даже преобразовать в Интс, вы будете нуждаться, чтобы разбить строку вверх на ее компоненты:

  • +
  • 2,0
  • +
  • +

Это потребует рекурсивный парсер, который (видя, как вы новичок в Python), может быть немного препятствие.

Предполагая, что теперь у вас есть каждая часть отдельно в виде строк,

float("2.0") = 2.0 
int(2.0) = 2 

Вот вспомогательная функция

def num (s): 
    try: 
     return int(s) 
    except exceptions.ValueError: 
     return int(float(s)) 
+0

Хорошо, да, это то, что я хотел сделать ... рекурсивный синтаксический анализатор. Ну, я знаю все основы Python, поэтому я считаю, что единственный способ узнать что-то новое - попробовать что-то довольно сложное. Что такое рекурсивный парсер и как он используется? Просто ссылка будет прекрасной, если вы не захотите ее объяснить. – 2013-05-09 00:46:28

+0

Почему 'int (float (s))'? –

+0

Я предполагал, что он только хотел разобрать ints. aka convert 2.0 to 2 и т. д. Очевидно, что если он действительно хотел разобрать поплавки, просто введите тип float и поднимите синтаксисError, если он не работает. – aong152

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). Он не обсуждает это, но если вы внимательно посмотрите , это также вытекает из структуры грамматики. Не тратьте деньги на это; просто знайте для будущей ссылки, что это называется ассоциативность.

  • Результатом анализа является дерево. Затем вы можете вычислить его значение снизу вверх. В разделе «Расчет!» глава он делает это, но в виде волшебного пути. Не беспокойтесь об этом.


Чтобы построить калькулятор самостоятельно, я предлагаю вам раздеться проблему как можно больше.

  1. Узнав, где заканчивается номер и т. Д., Это немного грязно. Он может быть частью грамматики или выполнен отдельным проходом под названием lexer или tokenizer.
    Я предлагаю вам пропустить его - требуется, чтобы пользователь вводил пробелы вокруг всех операторов и парнеров. Или просто предположим, что вам уже дан список формы [2.0, "*", "(", 3.0, "+", -1.0, ")"].

  2. Начать с тривиальной функции парсера (токенов), которая обрабатывает только 3-элементные выражения - [число, op, число].
    Возвратите одно число, результат вычисления. (Я ранее сказал, что синтаксические анализаторы выводят дерево, которое обрабатывается позже. Не беспокойтесь об этом, возвращая число проще.)

  3. Напишите функцию, которая ожидает число или скобки - в последнем случае он вызывает парсер().

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

    Обратите внимание, что я возвращаю второе значение - оставшуюся часть ввода. Измените parser(), чтобы использовать это соглашение.

  4. Теперь перепишите парсер(), чтобы вызвать number_or_expr() вместо того, чтобы непосредственно принимать маркеры [0], а токены [2] - это числа.
    Виола! Теперь у вас есть (взаимно) рекурсивный калькулятор, который может вычислить что угодно - он просто должен быть написан в многословном стиле с помощью парсеров вокруг всего.

Теперь остановитесь и полюбуйтесь код, по крайней мере один день :-) Это еще простой, но имеет существенный рекурсивный характер синтаксического анализа. И структура кода отражает грамматику 1: 1 (что является хорошим свойством рекурсивного спуска. Вы не хотите знать, как выглядят другие алгоритмы).

Отсюда множество улучшений возможно - поддержка 2 + 2 + 2, позволяют (1), старшинство ... - но есть 2 способа идти об этом:

  • совершенствуй свой шаг за шагом кода , Вам придется реорганизовать много.
  • Прекратите работать и используйте библиотеку разбора, например. pyparsing. Это позволит вам быстрее экспериментировать с изменениями грамматики.

 Смежные вопросы

  • Нет связанных вопросов^_^