|
1 |
| -import string |
| 1 | +""" |
| 2 | +https://en.wikipedia.org/wiki/Infix_notation |
| 3 | +https://en.wikipedia.org/wiki/Reverse_Polish_notation |
| 4 | +https://en.wikipedia.org/wiki/Shunting-yard_algorithm |
| 5 | +""" |
2 | 6 |
|
| 7 | +from .balanced_parentheses import balanced_parentheses |
3 | 8 | from .stack import Stack
|
4 | 9 |
|
5 |
| -__author__ = "Omkar Pathak" |
6 | 10 |
|
7 |
| - |
8 |
| -def is_operand(char): |
9 |
| - return char in string.ascii_letters or char in string.digits |
10 |
| - |
11 |
| - |
12 |
| -def precedence(char): |
13 |
| - """Return integer value representing an operator's precedence, or |
| 11 | +def precedence(char: str) -> int: |
| 12 | + """ |
| 13 | + Return integer value representing an operator's precedence, or |
14 | 14 | order of operation.
|
15 |
| -
|
16 | 15 | https://en.wikipedia.org/wiki/Order_of_operations
|
17 | 16 | """
|
18 |
| - dictionary = {"+": 1, "-": 1, "*": 2, "/": 2, "^": 3} |
19 |
| - return dictionary.get(char, -1) |
20 |
| - |
| 17 | + return {"+": 1, "-": 1, "*": 2, "/": 2, "^": 3}.get(char, -1) |
21 | 18 |
|
22 |
| -def infix_to_postfix(expression): |
23 |
| - """Convert infix notation to postfix notation using the Shunting-yard |
24 |
| - algorithm. |
25 | 19 |
|
26 |
| - https://en.wikipedia.org/wiki/Shunting-yard_algorithm |
27 |
| - https://en.wikipedia.org/wiki/Infix_notation |
28 |
| - https://en.wikipedia.org/wiki/Reverse_Polish_notation |
| 20 | +def infix_to_postfix(expression_str: str) -> str: |
| 21 | + """ |
| 22 | + >>> infix_to_postfix("(1*(2+3)+4))") |
| 23 | + Traceback (most recent call last): |
| 24 | + ... |
| 25 | + ValueError: Mismatched parentheses |
| 26 | + >>> infix_to_postfix("") |
| 27 | + '' |
| 28 | + >>> infix_to_postfix("3+2") |
| 29 | + '3 2 +' |
| 30 | + >>> infix_to_postfix("(3+4)*5-6") |
| 31 | + '3 4 + 5 * 6 -' |
| 32 | + >>> infix_to_postfix("(1+2)*3/4-5") |
| 33 | + '1 2 + 3 * 4 / 5 -' |
| 34 | + >>> infix_to_postfix("a+b*c+(d*e+f)*g") |
| 35 | + 'a b c * + d e * f + g * +' |
| 36 | + >>> infix_to_postfix("x^y/(5*z)+2") |
| 37 | + 'x y ^ 5 z * / 2 +' |
29 | 38 | """
|
30 |
| - stack = Stack(len(expression)) |
| 39 | + if not balanced_parentheses(expression_str): |
| 40 | + raise ValueError("Mismatched parentheses") |
| 41 | + stack = Stack() |
31 | 42 | postfix = []
|
32 |
| - for char in expression: |
33 |
| - if is_operand(char): |
| 43 | + for char in expression_str: |
| 44 | + if char.isalpha() or char.isdigit(): |
34 | 45 | postfix.append(char)
|
35 |
| - elif char not in {"(", ")"}: |
36 |
| - while not stack.is_empty() and precedence(char) <= precedence(stack.peek()): |
37 |
| - postfix.append(stack.pop()) |
38 |
| - stack.push(char) |
39 | 46 | elif char == "(":
|
40 | 47 | stack.push(char)
|
41 | 48 | elif char == ")":
|
42 | 49 | while not stack.is_empty() and stack.peek() != "(":
|
43 | 50 | postfix.append(stack.pop())
|
44 |
| - # Pop '(' from stack. If there is no '(', there is a mismatched |
45 |
| - # parentheses. |
46 |
| - if stack.peek() != "(": |
47 |
| - raise ValueError("Mismatched parentheses") |
48 | 51 | stack.pop()
|
| 52 | + else: |
| 53 | + while not stack.is_empty() and precedence(char) <= precedence(stack.peek()): |
| 54 | + postfix.append(stack.pop()) |
| 55 | + stack.push(char) |
49 | 56 | while not stack.is_empty():
|
50 | 57 | postfix.append(stack.pop())
|
51 | 58 | return " ".join(postfix)
|
52 | 59 |
|
53 | 60 |
|
54 | 61 | if __name__ == "__main__":
|
| 62 | + from doctest import testmod |
| 63 | + |
| 64 | + testmod() |
55 | 65 | expression = "a+b*(c^d-e)^(f+g*h)-i"
|
56 | 66 |
|
57 | 67 | print("Infix to Postfix Notation demonstration:\n")
|
|
0 commit comments