2020-11-01 16:35:31 +00:00
|
|
|
"""
|
|
|
|
https://en.wikipedia.org/wiki/Infix_notation
|
|
|
|
https://en.wikipedia.org/wiki/Reverse_Polish_notation
|
|
|
|
https://en.wikipedia.org/wiki/Shunting-yard_algorithm
|
|
|
|
"""
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2020-11-01 16:35:31 +00:00
|
|
|
from .balanced_parentheses import balanced_parentheses
|
2019-07-31 15:14:35 +00:00
|
|
|
from .stack import Stack
|
2018-10-19 12:48:28 +00:00
|
|
|
|
|
|
|
|
2020-11-01 16:35:31 +00:00
|
|
|
def precedence(char: str) -> int:
|
|
|
|
"""
|
|
|
|
Return integer value representing an operator's precedence, or
|
2018-10-19 12:48:28 +00:00
|
|
|
order of operation.
|
|
|
|
https://en.wikipedia.org/wiki/Order_of_operations
|
|
|
|
"""
|
2020-11-01 16:35:31 +00:00
|
|
|
return {"+": 1, "-": 1, "*": 2, "/": 2, "^": 3}.get(char, -1)
|
2018-10-19 12:48:28 +00:00
|
|
|
|
|
|
|
|
2020-11-01 16:35:31 +00:00
|
|
|
def infix_to_postfix(expression_str: str) -> str:
|
|
|
|
"""
|
|
|
|
>>> infix_to_postfix("(1*(2+3)+4))")
|
|
|
|
Traceback (most recent call last):
|
2022-10-27 17:42:30 +00:00
|
|
|
...
|
2020-11-01 16:35:31 +00:00
|
|
|
ValueError: Mismatched parentheses
|
|
|
|
>>> infix_to_postfix("")
|
|
|
|
''
|
|
|
|
>>> infix_to_postfix("3+2")
|
|
|
|
'3 2 +'
|
|
|
|
>>> infix_to_postfix("(3+4)*5-6")
|
|
|
|
'3 4 + 5 * 6 -'
|
|
|
|
>>> infix_to_postfix("(1+2)*3/4-5")
|
|
|
|
'1 2 + 3 * 4 / 5 -'
|
|
|
|
>>> infix_to_postfix("a+b*c+(d*e+f)*g")
|
|
|
|
'a b c * + d e * f + g * +'
|
|
|
|
>>> infix_to_postfix("x^y/(5*z)+2")
|
|
|
|
'x y ^ 5 z * / 2 +'
|
2018-10-19 12:48:28 +00:00
|
|
|
"""
|
2020-11-01 16:35:31 +00:00
|
|
|
if not balanced_parentheses(expression_str):
|
|
|
|
raise ValueError("Mismatched parentheses")
|
2021-10-26 18:33:08 +00:00
|
|
|
stack: Stack[str] = Stack()
|
2018-10-19 12:48:28 +00:00
|
|
|
postfix = []
|
2020-11-01 16:35:31 +00:00
|
|
|
for char in expression_str:
|
|
|
|
if char.isalpha() or char.isdigit():
|
2018-10-19 12:48:28 +00:00
|
|
|
postfix.append(char)
|
2019-10-05 05:14:13 +00:00
|
|
|
elif char == "(":
|
2018-10-19 12:48:28 +00:00
|
|
|
stack.push(char)
|
2019-10-05 05:14:13 +00:00
|
|
|
elif char == ")":
|
|
|
|
while not stack.is_empty() and stack.peek() != "(":
|
2018-10-19 12:48:28 +00:00
|
|
|
postfix.append(stack.pop())
|
|
|
|
stack.pop()
|
2020-11-01 16:35:31 +00:00
|
|
|
else:
|
|
|
|
while not stack.is_empty() and precedence(char) <= precedence(stack.peek()):
|
|
|
|
postfix.append(stack.pop())
|
|
|
|
stack.push(char)
|
2018-10-19 12:48:28 +00:00
|
|
|
while not stack.is_empty():
|
|
|
|
postfix.append(stack.pop())
|
2019-10-05 05:14:13 +00:00
|
|
|
return " ".join(postfix)
|
2018-10-19 12:48:28 +00:00
|
|
|
|
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
if __name__ == "__main__":
|
2020-11-01 16:35:31 +00:00
|
|
|
from doctest import testmod
|
|
|
|
|
|
|
|
testmod()
|
2019-10-05 05:14:13 +00:00
|
|
|
expression = "a+b*(c^d-e)^(f+g*h)-i"
|
2018-10-19 12:48:28 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
print("Infix to Postfix Notation demonstration:\n")
|
|
|
|
print("Infix notation: " + expression)
|
|
|
|
print("Postfix notation: " + infix_to_postfix(expression))
|