| 1 | 1 | def answer(question: str) -> int: |
| 2 | | pass |
| 2 | """ |
| 3 | Parse and evaluate a simple math word problem. |
| 4 | |
| 5 | Args: |
| 6 | question: A string representing a math word problem. |
| 7 | |
| 8 | Returns: |
| 9 | An integer result of evaluating the math expression. |
| 10 | |
| 11 | Raises: |
| 12 | ValueError: If the question is malformed, contains unknown operations, |
| 13 | or is not a math question. |
| 14 | """ |
| 15 | # Edge Case: Non-math questions |
| 16 | if not question.startswith("What is"): |
| 17 | raise ValueError("unknown operation") |
| 18 | |
| 19 | # Remove the "What is" prefix and the trailing question mark |
| 20 | expression = question[8:-1].strip() |
| 21 | |
| 22 | # Edge Case: Empty expression after "What is" |
| 23 | if not expression: |
| 24 | raise ValueError("syntax error") |
| 25 | |
| 26 | # Tokenize the expression |
| 27 | tokens = [] |
| 28 | i = 0 |
| 29 | while i < len(expression): |
| 30 | if expression[i].isspace(): |
| 31 | i += 1 |
| 32 | continue |
| 33 | elif expression[i].isdigit() or (expression[i] == '-' and i < len(expression) - 1 and expression[i+1].isdigit()): |
| 34 | # Parse negative numbers |
| 35 | start = i |
| 36 | if expression[i] == '-': |
| 37 | i += 1 |
| 38 | while i < len(expression) and (expression[i].isdigit() or expression[i] == '.'): |
| 39 | i += 1 |
| 40 | # Edge Case: Numbers with decimal points |
| 41 | num_str = expression[start:i] |
| 42 | if '.' in num_str: |
| 43 | try: |
| 44 | num = float(num_str) |
| 45 | # Edge Case: Non-integer numbers |
| 46 | if not num.is_integer(): |
| 47 | raise ValueError("syntax error") |
| 48 | tokens.append(int(num)) |
| 49 | except ValueError: |
| 50 | raise ValueError("syntax error") |
| 51 | else: |
| 52 | tokens.append(int(num_str)) |
| 53 | else: |
| 54 | # Parse operators and words |
| 55 | start = i |
| 56 | while i < len(expression) and not expression[i].isspace(): |
| 57 | i += 1 |
| 58 | word = expression[start:i] |
| 59 | if word == "plus": |
| 60 | tokens.append("+") |
| 61 | elif word == "minus": |
| 62 | tokens.append("-") |
| 63 | elif word == "multiplied": |
| 64 | # Check for "by" after "multiplied" |
| 65 | if i >= len(expression) or not expression[i:].lstrip().startswith("by"): |
| 66 | raise ValueError("syntax error") |
| 67 | # Skip "by" and add multiplication operator |
| 68 | j = i |
| 69 | while j < len(expression) and expression[j].isspace(): |
| 70 | j += 1 |
| 71 | j += 2 # Skip "by" |
| 72 | i = j |
| 73 | tokens.append("*") |
| 74 | elif word == "divided": |
| 75 | # Check for "by" after "divided" |
| 76 | if i >= len(expression) or not expression[i:].lstrip().startswith("by"): |
| 77 | raise ValueError("syntax error") |
| 78 | # Skip "by" and add division operator |
| 79 | j = i |
| 80 | while j < len(expression) and expression[j].isspace(): |
| 81 | j += 1 |
| 82 | j += 2 # Skip "by" |
| 83 | i = j |
| 84 | tokens.append("/") |
| 85 | else: |
| 86 | # Edge Case: Unknown operations |
| 87 | raise ValueError("unknown operation") |
| 88 | |
| 89 | # Edge Case: Empty tokens list |
| 90 | if not tokens: |
| 91 | raise ValueError("syntax error") |
| 92 | |
| 93 | # Edge Case: Expression starting with an operator |
| 94 | if isinstance(tokens[0], str): |
| 95 | raise ValueError("syntax error") |
| 96 | |
| 97 | # Evaluate the expression from left to right |
| 98 | result = tokens[0] |
| 99 | i = 1 |
| 100 | |
| 101 | # Edge Case: Odd number of tokens (missing operator or operand) |
| 102 | if len(tokens) % 2 == 0: |
| 103 | raise ValueError("syntax error") |
| 104 | |
| 105 | while i < len(tokens): |
| 106 | # Edge Case: Missing operator between numbers |
| 107 | if not isinstance(tokens[i], str): |
| 108 | raise ValueError("syntax error") |
| 109 | |
| 110 | operator = tokens[i] |
| 111 | # Edge Case: Missing operand after operator |
| 112 | if i + 1 >= len(tokens): |
| 113 | raise ValueError("syntax error") |
| 114 | |
| 115 | # Edge Case: Operator where operand should be |
| 116 | if isinstance(tokens[i + 1], str): |
| 117 | raise ValueError("syntax error") |
| 118 | |
| 119 | operand = tokens[i + 1] |
| 120 | |
| 121 | if operator == "+": |
| 122 | result += operand |
| 123 | elif operator == "-": |
| 124 | result -= operand |
| 125 | elif operator == "*": |
| 126 | result *= operand |
| 127 | elif operator == "/": |
| 128 | # Edge Case: Division by zero |
| 129 | if operand == 0: |
| 130 | raise ValueError("syntax error") # Or we could raise ZeroDivisionError |
| 131 | result //= operand # Integer division as per examples |
| 132 | else: |
| 133 | # This shouldn't happen due to earlier validation, but just in case |
| 134 | raise ValueError("unknown operation") |
| 135 | |
| 136 | i += 2 |
| 137 | |
| 138 | return result |
| 139 | # Handled Edge Cases: Non-math questions, Empty expression, Numbers with decimal points, Non-integer numbers, Expression starting with an operator, Odd number of tokens, Missing operator between numbers, Missing operand after operator, Operator where operand should be, Division by zero, Unknown operations, Empty tokens list |