Normalize the answer string for comparison.
(answer: str)
| 408 | return None |
| 409 | |
| 410 | def normalize_answer(answer: str) -> str: |
| 411 | """Normalize the answer string for comparison.""" |
| 412 | logger.debug(f"Normalizing answer: {repr(answer)}") |
| 413 | |
| 414 | if answer is None: |
| 415 | logger.debug("Received None answer") |
| 416 | return "" |
| 417 | |
| 418 | # Remove \text{} with units first |
| 419 | answer = re.sub(r'\\text{[^}]+(?:inches|feet|meters|cm|m|kg|ft|in|lb|oz|ml|L|per|second|minute|hour)[^}]*}', '', answer) |
| 420 | |
| 421 | |
| 422 | # Remove all whitespace first but preserve backslash space temporarily |
| 423 | answer = re.sub(r'(?<!\\)\s+', '', answer) |
| 424 | logger.debug(f"After initial whitespace removal: {repr(answer)}") |
| 425 | |
| 426 | # Then handle ordered pairs/tuples with potential \left, \right |
| 427 | ordered_pair_match = re.match(r'^(?:\\left)?\((.*?)(?:\\right)?\)$', answer) |
| 428 | if ordered_pair_match: |
| 429 | content = ordered_pair_match.group(1) |
| 430 | # Split by comma and normalize each part |
| 431 | parts = content.split(',') |
| 432 | normalized_parts = [] |
| 433 | for part in parts: |
| 434 | # Remove any remaining backslash spaces |
| 435 | part = re.sub(r'\\?\s+', '', part) |
| 436 | norm_part = normalize_answer(part) |
| 437 | if norm_part is None: |
| 438 | return None |
| 439 | normalized_parts.append(norm_part) |
| 440 | return f"({','.join(normalized_parts)})" |
| 441 | |
| 442 | # Remove all whitespace |
| 443 | answer = ''.join(answer.split()) |
| 444 | logger.debug(f"After whitespace removal: {repr(answer)}") |
| 445 | |
| 446 | if not answer: |
| 447 | logger.debug("Answer became empty after whitespace removal") |
| 448 | return None |
| 449 | |
| 450 | # Handle plus-minus expressions first |
| 451 | # This will match both forms: "a \pm b" and "a - b" |
| 452 | pm_match = re.match(r'^(.*?)(?:\\pm|-)(.*?)$', answer) |
| 453 | if pm_match: |
| 454 | left, right = pm_match.groups() |
| 455 | # Normalize both sides |
| 456 | norm_left = normalize_answer(left) if left else "" |
| 457 | norm_right = normalize_answer(right) if right else "" |
| 458 | if norm_left or norm_right: # If either side normalized successfully |
| 459 | # Always use \pm in the normalized form |
| 460 | result = f"{norm_left}\\pm{norm_right}" |
| 461 | logger.debug(f"Matched as plus-minus expression: {repr(result)}") |
| 462 | return result |
| 463 | |
| 464 | # Handle trigonometric functions |
| 465 | trig_match = re.match(r'^\\(?:sin|cos|tan|cot|sec|csc)\s*([a-zA-Z])$', answer) |
| 466 | if trig_match: |
| 467 | variable = trig_match.group(1) |
no test coverage detected