views:

192

answers:

4

Beginner in python, but been programming for about 5 years now. I suspect I have a lot to learn about doing things the object oriented way, but I know the basics. I planned on programming a calculator that shows it's work for the challenge and knowledge i'll gain from it. I just started and this is what i've got, and it just looks really ugly to me. How would you have done it differently?

P.S. This is just a simple script to take the problem from inside parenthesis, add it up, show the work, then evaluate the full problem.

import re

def EvalParenths(problem):
    contents = ""
    if re.match( "\(", problem):
     contents = re.match("(\(.*\))", problem)
     parenthsAnswer = contents.group(0)
     problem = problem.replace(parenthsAnswer, '')
     print "   \ \n   "  + str(eval(parenthsAnswer)) + problem
     problem = problem.replace(parenthsAnswer, '')
     answer = eval(parenthsAnswer+problem)
     print "    \ \n    " + str(answer)
    else:
     print "Didn't Find Parenthesis"

def ProblemHasParenths(problem):
    return re.match( "\(", problem)

"""""
Example Problem: (12/4)*2

"""""

problem = raw_input()

if ProblemHasParenths:
    EvalParenths(problem)
+1  A: 

If you want to make a simple calculator you could try implementing Shunting-yard algorithm.

But if you want to go with regex approach I'd still do it a little differently:

import re

#In python functions/methods usually are lowercase
#and words are seperated by _ while classes use CamelCasing
def eval_step_by_step(expression):
    """Evaluates math expression. Doesn't do any error checking.
        expression (string) - math expression"""

    print expression
    #For pretty formating.
    expr_len = len(expression)
    #While there's parentheses in the expression.
    while True:
        #re.match checks for a match only at the beginning of the string,
        #while re.search checks for a match anywhere in the string.

        #Matches all numbers, +, -, *, / and whitespace within parentheses
        #lazily (innermost first).
        contents = re.search("\(([0-9|\*|/|\+|\-|\s]*?)\)", expression) 
        #If we didn't find anything, print result and break out of loop.
        if not contents:
            #string.format() is the Python 3 way of formating strings
            #(Also works in Python 2.6).

            #Print eval(expression) aligned right in a "field" with width
            #of expr_len characters.
            print "{0:{1}}".format(eval(expression), expr_len)
            break

        #group(0) [match] is everything matching our search,
        #group(1) [parentheses_text] is just epression withing parentheses.
        match, parentheses_text = contents.group(0), contents.group(1)
        expression = expression.replace(match, str(eval(parentheses_text)))
        #Aligns text to the right. Have to use ">" here
        #because expression is not a number.
        print "{0:>{1}}".format(expression, expr_len)

#For example try: (4+3+(32-1)*3)*3
problem = raw_input("Input math problem: ")

eval_step_by_step(problem)

It doesn't exactly work the same as your function, but you could easily implement modifications into your function to match mine. As you can see, I've also added a lot of comments to explain some stuff.

Maiku Mori
Thanks for the algo recommendation. No rush on the rewrite, i'm about to go to bed anyway :)I'm reading up on the shunting-yard algo right now!
Codygman
BTW, the reason i'm wanting to make a calculator that shows steps is I believe it will help me get into artificial intelligence type programming
Codygman
I've updated with some code, sorry for delay something came up.
Maiku Mori
Oh yeah, you could also write it using recursion (probably more pythonic).
Maiku Mori
+4  A: 

Some problems:

contents = re.match("(\(.*\))", problem)

When it's given the input (1+2)/(3+4), it's going to try to evaluate 1+2)/(3+4.

It also doesn't go all the way into nested parentheses, for this you would need to use recursion.

I think you should make another attempt at this before you "look at the answers".

Artelius
Will do when I get up in the morning!Thanks for the advice
Codygman
A: 

Why don't you match only for the double and matching parentheses? The first match for a single ( is not really necessary because if the match for the doubles fail, this means there are no expression for you to evaluate.

import re

def eval_parentheses(problem):
    contents = re.match("(\(.*\))", problem)
    if contents:
    ...
    else:
        print "Couldn't find parentheses!"

Also, the parentheses selection algorithm could be improved a bit for nested parens etc.

Tamás Mezei
+2  A: 

I'd probably replace occurrences of

re.match( "\(", problem)

with

problem.startswith("(")

In

contents = re.match("(\(.*\))", problem)
parenthsAnswer = contents.group(0)

you don't check to see whether contents matches or not so if you pass it the input "(1" you'll get an exception when you try to evaluate contents.group(0)

Don't every use eval in a real program!

You could use pyparsing to make a full parser, but I think it is the kind of thing everyone should try on their own as an exercise at least once!

Nick Craig-Wood