Guest User

Untitled

a guest
Oct 21st, 2018
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.09 KB | None | 0 0
  1. import re
  2. import math
  3. import operator
  4.  
  5. def shunting_yard(exp):
  6. """ Converts expressions from infix to postfix notation
  7.  
  8. >>> shunting_yard("5 + 6")
  9. ['5', '6', '+']
  10. >>> shunting_yard("9 + (5 * 2) + 3 / 4")
  11. ['9', '5', '2', '*', '+', '3', '4', '/', '+']
  12.  
  13. Args:
  14. A string expression in infix notation
  15.  
  16. Returns:
  17. A list expression in postfix notation
  18.  
  19. """
  20. operator_precedence = {'+': 2, '-': 2,
  21. '*': 3, '/': 3, '%' : 3,
  22. '^': 4}
  23. operator_associativity = {'+': 'left', '-': 'left',
  24. '*': 'left', '/': 'left', '%' : 'left',
  25. '^': 'right'}
  26. valid_token = re.compile("[-]?[0-9]*\.[0-9]+|[-]?[0-9]+|[+-/^*()%]")
  27. valid_operator = re.compile("[+-/%*^]")
  28. valid_number = re.compile("[-]?[0-9]*\.[0-9]+|[0-9]+")
  29.  
  30. exp = valid_token.findall(exp)
  31. output_queue = []
  32. operator_stack = []
  33. for token in exp:
  34. #Numbers can added to the queue in their original order
  35. if valid_number.search(token):
  36. output_queue.append(token)
  37. #Match only single characters that match the regex, e.g. not "-5"
  38. if valid_operator.search(token) and len(token) == 1:
  39. try: #Queue might be empty, will throw KeyError exception
  40. #Pop off operators and add them to the queue depending on
  41. #precedence and associativity.
  42. while (len(operator_stack) > 0 and
  43. ((operator_associativity[token] == 'left' and
  44. operator_precedence[token] <=
  45. operator_precedence[operator_stack[-1]]) or
  46. (operator_associativity[token] == 'right' and
  47. operator_precedence[token] <
  48. operator_precedence[operator_stack[-1]]))):
  49. output_queue.append(operator_stack.pop())
  50. except KeyError:
  51. pass
  52. operator_stack.append(token)
  53. #Pop off operators inside parens until a closing paren is met
  54. if token == "(":
  55. operator_stack.append(token)
  56. if token == ")":
  57. while True:
  58. operator = operator_stack.pop()
  59. if operator == "(":
  60. break
  61. else:
  62. output_queue.append(operator)
  63. #Empty the stack if it is still full
  64. while len(operator_stack) > 0:
  65. output_queue.append(operator_stack.pop())
  66. return output_queue
  67.  
  68. def postfix_evaluator(exp):
  69. """ Evaluates postfix mathematical expressions
  70.  
  71. >>> postfix_evaluator(["-5","3","8","+","*"])
  72. -55.0
  73.  
  74. Args:
  75. A list expression in post-fix notation containing only
  76.  
  77. Returns:
  78. The evaluation of the expression, as a float
  79.  
  80. """
  81.  
  82. op_dict = {'+': operator.add,
  83. '-': operator.sub,
  84. '*': operator.mul,
  85. '/': operator.truediv,
  86. '%': operator.mod,
  87. '^': math.pow}
  88. operand_stack = []
  89.  
  90. valid_operator = re.compile("[+-/%*^]")
  91. valid_number = re.compile("[-]?[0-9]*\.[0-9]+|[0-9]+")
  92. #Place operands on the stack in the order they are encountered
  93. #When an operator is encountered, use it to operate on the last
  94. #two operands on the stack and push the result onto the stack
  95. for token in exp:
  96. if valid_number.search(token):
  97. operand_stack.append(token)
  98. if valid_operator.search(token) and len(token) == 1:
  99. operand2, operand1 = operand_stack.pop(), operand_stack.pop()
  100. operand_stack.append(op_dict[token](float(operand1),
  101. float(operand2)))
  102. return operand_stack.pop()
  103.  
  104. def evaluator(expression):
  105. """ Evaluates an infix-notated expression
  106.  
  107. Args:
  108. A string expression in infix notation containing real numbers and
  109. operators (including +, -, *, /, %, and ^)
  110.  
  111. Returns:
  112. The evaluation of the expression, as a float
  113.  
  114. """
  115. return postfix_evaluator((shunting_yard(expression)))
  116.  
  117. if __name__ == "__main__":
  118. import doctest
  119. doctest.testmod()
Add Comment
Please, Sign In to add comment