"""Roman numeral parsing helpers.""" import re _ROMAN_VALID_RE = re.compile( r"^M{0,3}(CM|CD|D?C{0,3})" r"(XC|XL|L?X{0,3})" r"(IX|IV|V?I{0,3})$" ) _ROMAN_TOKEN_RE = re.compile(r"(? int | None: if not token: return None roman = token.strip().upper() if not roman or not _ROMAN_VALID_RE.fullmatch(roman): return None total = 0 prev = 0 for char in reversed(roman): value = _ROMAN_VALUES[char] if value < prev: total -= value else: total += value prev = value return total def replace_roman_numerals(text: str) -> str: if not text: return text def _repl(match: re.Match) -> str: token = match.group(0) value = roman_to_int(token) return str(value) if value is not None else token return _ROMAN_TOKEN_RE.sub(_repl, text)