SIMPLE = { "I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000, } SIMPLE_REVERSE = {v: k for k, v in SIMPLE.items()} COMPOUND = { "IV": 4, "IX": 9, "XL": 40, "XC": 90, "CD": 400, "CM": 900, } PREFIXES = {k[0] for k in COMPOUND.keys()} COMPOUND_REVERSE = {v: k for k, v in COMPOUND.items()} ALL = SIMPLE | COMPOUND ALL_REVERSE = {v: k for k, v in ALL.items()} def i2r(i: int) -> str: if i > 100_000: raise ValueError(f"{i} is too silly") r: list[str] = [] for int_val, roman_val in sorted(ALL_REVERSE.items(), reverse=True): remainder = i % int_val r += [roman_val] * int((i - remainder) / int_val) i = remainder return "".join(r) def r2i(r: str) -> int: total = 0 offset = 0 for i in range(len(r)): if i + offset > len(r) - 1: break c = r[i + offset] if c in PREFIXES and (i + offset + 1) < len(r) and c + r[i + offset + 1] in ALL: total += ALL[c + r[i + offset + 1]] offset += 1 continue total += ALL[c] return total