I am trying to write an Infix to Prefix Converter where e.g. I would like to convert this:
1 + ((C + A ) * (B - F))
to something like:
add(1, multiply(add(C, A), subtract(B, F)))
but I get this instead :
multiply(add(1, add(C, A), subtract(B, F)))
This is the code I have so far
postfix = []
temp = []
newTemp = []
def textOperator(s):
if s is '+':
return 'add('
elif s is '-':
return 'subtract('
elif s is '*':
return 'multiply('
else:
return ""
def typeof(s):
if s is '(':
return leftparentheses
elif s is ')':
return rightparentheses
elif s is '+' or s is '-' or s is '*' or s is '%' or s is '/':
return operator
elif s is ' ':
return empty
else :
return operand
infix = "1 + ((C + A ) * (B - F))"
for i in infix :
type = typeof(i)
if type is operand:
newTemp.append(i)
elif type is operator:
postfix.append(textOperator(i))
postfix.append(newTemp.pop())
postfix.append(', ')
elif type is leftparentheses :
newTemp.append(i)
elif type is rightparentheses :
next = newTemp.pop()
while next is not '(':
postfix.append(next)
next = newTemp.pop()
postfix.append(')')
newTemp.append(''.join(postfix))
while len(postfix) > 0 :
postfix.pop()
elif type is empty:
continue
print("newTemp = ", newTemp)
print("postfix = ", postfix)
while len(newTemp) > 0 :
postfix.append(newTemp.pop())
postfix.append(')')
print(''.join(postfix))
Can someone please help me figure out how I would fix this.
What I see, with the parenthetical clauses, is a recursive problem crying out for a recursive solution. The following is a rethink of your program that might give you some ideas of how to restructure it, even if you don't buy into my recursion argument:
import sys
from enum import Enum
class Type(Enum): # This could also be done with individual classes
leftparentheses = 0
rightparentheses = 1
operator = 2
empty = 3
operand = 4
OPERATORS = { # get your data out of your code...
"+": "add",
"-": "subtract",
"*": "multiply",
"%": "modulus",
"/": "divide",
}
def textOperator(string):
if string not in OPERATORS:
sys.exit("Unknown operator: " + string)
return OPERATORS[string]
def typeof(string):
if string == '(':
return Type.leftparentheses
elif string == ')':
return Type.rightparentheses
elif string in OPERATORS:
return Type.operator
elif string == ' ':
return Type.empty
else:
return Type.operand
def process(tokens):
stack = []
while tokens:
token = tokens.pop()
category = typeof(token)
print("token = ", token, " (" + str(category) + ")")
if category == Type.operand:
stack.append(token)
elif category == Type.operator:
stack.append((textOperator(token), stack.pop(), process(tokens)))
elif category == Type.leftparentheses:
stack.append(process(tokens))
elif category == Type.rightparentheses:
return stack.pop()
elif category == Type.empty:
continue
print("stack = ", stack)
return stack.pop()
INFIX = "1 + ((C + A ) * (B - F))"
# pop/append work from right, so reverse, and require a real list
postfix = process(list(INFIX[::-1]))
print(postfix)
The result of this program is a structure like:
('add', '1', ('multiply', ('add', 'C', 'A'), ('subtract', 'B', 'F')))
Which you should be able to post process into the string form you desire (again, recursively...)
PS: type and next are Python built-ins and/or reserved words, don't use them for variable names.
PPS: replace INFIX[::-1] with sys.argv[1][::-1] and you can pass test cases into the program to see what it does with them.
PPPS: like your original, this only handles single digit numbers (or single letter variables), you'll need to provide a better tokenizer than list() to get that working right.
Related
I am trying to write a python program to evaluate a string expression and return an output. The program works perfectly except for the part where I have to evaluate the expression written within brackets.
Here is the code responsible for evaluating the expression within brackets while following the BODMAS rule:
def evaluateExpression(expression):
for i in range(len(expression)):
if expression[i]=="(":
start = expression.index("(")
for j in range(start, len(expression)):
if(expression[j]==")"):
end = j
break
newExp = expression[start:end]
while "^" in newExp:
index = newExp.index("^")
newExp[index] = pow(newExp[index-1], newExp[index + 1])
while "*" in newExp or "/" in newExp:
for i in range(len(newExp)):
if newExp[i] == "*":
newExp[i] = int(newExp[i-1]) * int(newExp[i+1])
break
elif newExp[i] == "/":
newExp[i] = int(newExp[i-1]) / int(newExp[i+1])
break
while "+" in newExp or "-" in newExp:
for i in range(len(newExp)):
if newExp[i] == "+":
newExp[i] = int(newExp[i-1]) * int(newExp[i+1])
break
elif newExp[i] == "-":
newExp[i] = int(newExp[i-1]) * int(newExp[i+1])
break
expression[start:end] = newExp
else:
pass
I'm writing a program where I'm converting a function to prefix and calculate.
from pythonds.basic import Stack
def doMath(op, op1, op2):
if op == "*":
return int(op1) * int(op2)
elif op == "/":
return int(op1) / int(op2)
elif op == "+":
return int(op1) + int(op2)
elif op == "-":
return int(op1) + int(op2)
def postfixEval(postfixExpr):
operandStack = Stack()
tokenList = postfixExpr.split()
for token in tokenList:
print(tokenList)
print("this is token: ", token)
if token in "0123456789":
operandStack.push(token)
print("pop: ",operandStack.peek())
elif not operandStack.isEmpty():
operand2 = operandStack.pop()
operand1 = operandStack.pop()
result = doMath(token, operand1, operand2)
print (result)
operandStack.push(result)
return operandStack.pop()
print(postfixEval('7 8 + 3 2 + /'))
print(postfixEval("17 10 + 3 * 9 /"))
So when I run the first postfixEval it return 3.0,
but at the second print it returns IndexError: pop from empty list
Apparently it's bc of the 2 digit numbers, how could I fix that?
Thanks
When you try:
if token in "0123456789":
operandStack.push(token)
for token = 17, this shall fail since 17 is not in 0123456789.
So change it to this:
try:
if float(token):
operandStack.push(token)
except:
#your code here
HOW THIS WORKS:
When a type of str containing digits and numbers are passed, float() tries to convert it into float. This is only possible only if it is a number.
Replace if token in "0123456789" (checks if token is a substring of "0123456789") with if token.isdigit() (checks if token consists of decimal digits).
I am making a program which converting Prefix to Infix and I have a problem with putting brackets to expression.
For converting, I use classic stack algorithm. Here is my function for brackits.
Input:
//+86 16 67/*/31 53 85 15
My output:
((86+16)/67)/(((31/53)*85)/15)
Expecting output :
(86+16)/67/(31/53*85/15)
def breckets(operand1, operand2, operace):
res = ""
if (operand1.isdigit()) and (operand2.isdigit()):
res = operand1 + operace + operand2
elif (operand1.isdigit()) and (not operand2.isdigit()):
if operace == "+":
res = operand1 + operace + operand2
else:
res = operand1 + operace + "(" + operand2 + ")"
elif (not operand1.isdigit()) and (operand2.isdigit()):
if prior(operace) != 0:
res = "(" + operand1 + ")" + operace + operand2
else:
res = operand1 + operace + operand2
else:
res = "(" + operand1 + ")" + operace + "(" + operand2 + ")"
return res
def prior(a):
prior = None
if a in "+-":
prior = 0
elif a in "*/":
prior = 1
elif a in "^":
prior = 2
else:
print("Something went wrong")
exit()
return prior
But I must not use parentheses unnecessarily, can anybody advice me something please?
The code below can get what you expect. but I am not sure if the algorithm is right as I am not familiar with the data structure.
I use a basic function to sort the list several times, instead of sorting the list strictly from right to left, you can change some lines to break the while loop to make it so if that is what you want.
Anyway hope this can help you somehow.
operators = "+-*/^"
# presume the input is a finely spaced str that can be splitted into a proper list
# ipt = "/ * + 86 16 67 / * / + 31 53 85 15 / / 33 45 74" # for testing
ipt = "/ / + 86 16 67 / * / 31 53 85 15"
ip = ipt.split()
def sorting(lst):
res = []
i = len(lst)-1 # check list items from right to left
while i >= 0:
if i >= 3:
if lst[i-2] in operators:
# check if the operator is followed by two numbers
if lst[i-1] not in operators and lst[i] not in operators:
# check if the operator is + | -, the result should be in parentheses
if lst[i-2] in "+-":
res.append("(" + lst[i-1] + lst[i-2] + lst[i] + ")")
i -=3
continue
# if the operator is following another operator, the result shouldn't be in parentheses
if lst[i-3] in operators:
res.append(lst[i-1] + lst[i-2] + lst[i])
i -=3
continue
# if the operator is following a number, the result shouldn be in parentheses
else:
res.append("(" + lst[i-1] + lst[i-2] + lst[i] + ")")
i -= 3
continue
# this is to check the first item of the list is an operator and followed by two numbers
elif i == 2:
if lst[i-2] in operators:
if lst[i-1] not in operators and lst[i] not in operators:
res.append(lst[i-1] + lst[i-2] + lst[i])
i -=3
continue
res.append(lst[i])
i -= 1
# as all items are appending to the new list, so the positions are totally reversed
return list(reversed(res))
def no_more_operators(lst):
# to check if the lst is sortable
# one scenario is there are exccesive numbers, but no operators
# the current function can only check if any operators is in the list
for op in operators:
if op in lst:
return False
return True
def no_more_numbers(lst):
# to check if the lst is sortable
# one scenario is there are exccesive operators, but no numbers
# the current function can only check if any number is in the list
for i in lst:
if i.isnumeric():
return False
return True
# keep sorting the list until there is no more numbers or n0 more operators
while not no_more_numbers(ip) or not no_more_operators(ip):
ip = sorting(ip)
print(ip)
output:
['/', '/', '(86+16)', '67', '/', '*', '31/53', '85', '15']
['/', '(86+16)/67', '/', '31/53*85', '15']
['/', '(86+16)/67', '(31/53*85/15)']
['(86+16)/67/(31/53*85/15)']
I need to evaluate an expression from a string given such as "(19 + ((91 -96)-13))" but I have to make te algorithm myself, which I can't use eval() or something similar.
I've been tried alot with this code but it gives me problems with negative numbers:
while counter < 1:
chunks = []
counter2 = 1
for character in operation:
if character.isdigit():
if chunks[-1].isdigit(): # If the last chunk is already a number
chunks[-1] += character # Add onto that number
else:
chunks.append(character) # Start a new number chunk
elif character in '+-/*()':
chunks.append(character) # This doesn't account for `1 ++ 2`.
for e in reversed(chunks):
if e == '(':
counter2 = len(chunks) - counter2
break
else:
counter2 = counter2 + 1
if chunks[counter2+2] == '+':
result2 = int (chunks[counter2+1]) + int (chunks[counter2+3])
elif chunks[counter2+2] == '-':
result2 = int (chunks[counter2+1]) - int (chunks[counter2+3])
elif chunks[counter2+2] == '*':
result2 = int (chunks[counter2+1]) * int (chunks[counter2+3])
elif chunks[counter2+2] == '/':
result2 = int (chunks[counter2+1]) / int (chunks[counter2+3])
chunks[counter2] = ''
chunks[counter2 + 1] = ''
chunks[counter2 + 2] = str (result2)
chunks[counter2 + 3] = ''
chunks[counter2 + 4] = ''
operation = ''.join(chunks)
Don't pay attention to the while condition, I'm updating it as I need just to check
You should try to debug code more on your own. The problem you have is the int conversion is being done on "-" and not "-5". You need to combine "-" and integer next in the sequence and convert that to int and use.
temp = str(chunks[counter2+3]) + str(chunks[counter2+4])
This question already has answers here:
How to test multiple variables for equality against a single value?
(31 answers)
Why does "a == x or y or z" always evaluate to True? How can I compare "a" to all of those?
(8 answers)
Closed 9 years ago.
I am changing infix to postfix and then evaluating it.
#!/usr/bin/python
import sys
import fileinput
import operator
operator_functions = {
'+': operator.add,
'-': operator.sub,
'*': operator.mul,
'/': operator.div,
'%': operator.mod
}
def tokenise( line ) :
'''generator, serves up one token at a time
input - a valid, openo file handle (object)
output - next token (as a string)
side-effects - input pointer is moved'''
for tok in line.split() :
yield tok
#Define types with corresponding ID numbers to distinguish them.
OPERATOR = 1
OPERAND = 2
LEFT_PARENTHESES = 3
RIGHT_PARENTHESES = 4
def precedence(s): #Returns the precedence of the operators
if s == '(':
return 3
elif s == '+' or s == '-':
return 2
elif s == '*' or s == '/' or s == '%':
return 1
else:
return 0
def typeof(s): #Returns the type of the symbol
if s == '(':
return LEFT_PARENTHESES
elif s == ')':
return RIGHT_PARENTHESES
elif s == '+' or s == '-' or s == '*' or s == '%' or s == '/':
return OPERATOR
else :
return OPERAND
def infix2postfix(infix):
postfix = []
stack = []
for i in infix:
symbol_type = typeof(i)
if symbol_type == LEFT_PARENTHESES :
#If it is a left paren, push it onto the stack
stack.append(i)
elif symbol_type == RIGHT_PARENTHESES :
#If it is a right paren, pop operators from the stack and append to the postfix expression,
#until a left paren is encountered on the stack. Remove and discard the left paren
next = stack.pop()
while next != '(':
postfix.append(next)
next = stack.pop()
elif symbol_type == OPERAND:
#If it is an operand, append it to the postfix expression
postfix.append(i)
elif symbol_type == OPERATOR:
#If it is an operator, then pop operators from the stack and append to the postfix expression
#while the operators have equal or higher precedence than the current token. Push current
#token (operator) onto the stack
p = precedence(i)
#print i
while len(stack) != 0 and p <= precedence(stack[-1]) :
print stack
postfix.append(stack.pop())
stack.append(i)
while len(stack) > 0 : #Add to postfix
postfix.append(stack.pop())
evalPostfix(postfix) #Call evalPostFix to get result
def evalPostfix(postfix_expression):
stack = []
for token in postfix_expression :
if token in operator_functions:
no1 = int(stack.pop()) #First Number
no2 = int(stack.pop()) #Second Number
stack.append(operator_functions[token](no2, no1))
else :
stack.append(token)
print ' '.join(postfix_expression),'=',stack.pop() #The Result
##########
#Main Code
##########
if len(sys.argv) == 2: #Read from file
f = open( sys.argv[1] )
elif len(sys.argv) == 1: #Read from stdin
f = sys.stdin
else:
print 'Invalid Number of arguments. Supply either no arguments or an input file.'
sys.exit(0)
lines = [line.strip() for line in f]
for i in lines:
arr=[] #Array containing all infix expressions
tokens = tokenise( i )
for t in tokens :
#print t
arr.append(t)
infix2postfix(arr) #Call infix2postfix
Input example:
1 + 2 - 3
Output example:
1 2 + 3 - = 0
That works as desired, but when I try this:
Input:
13 + 23 - 42 * 2
I get
Output:
13 23 + 42 - 2 * = -12
Instead of:
13 23 + 42 2 * - = -48
I am not sure what is going wrong. Any ideas?
Use == instead of is operator , there is difference between is and ==, is check returns True when both objects are same == returns true if value are equal.
additionally, Condition:
s is '+' or '-':
Should be:
s == '+' or s == '-':
Note an non-empty string is always true e.g.
>>> bool('')
False
>>> bool('+')
True