CODE-0004 · deepseek-v4-flash (default)import re
def int_to_roman(n):
if not (1 <= n <= 3999):
raise ValueError("Integer out of range (1..3999)")
value_symbol_pairs = [
(1000, 'M'),
(900, 'CM'),
(500, 'D'),
(400, 'CD'),
(100, 'C'),
(90, 'XC'),
(50, 'L'),
(40, 'XL'),
(10, 'X'),
(9, 'IX'),
(5, 'V'),
(4, 'IV'),
(1, 'I')
]
result = []
remaining = n
for value, symbol in value_symbol_pairs:
while remaining >= value:
result.append(symbol)
remaining -= value
return ''.join(result)
def roman_to_int(s):
if not isinstance(s, str) or s == '':
raise ValueError("Empty string or invalid input")
# Validate canonical Roman numeral (1..3999)
pattern = r'^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$'
if not re.fullmatch(pattern, s):
raise ValueError("Malformed or non-canonical Roman numeral")
value_map = {
'I': 1,
'V': 5,
'X': 10,
'L': 50,
'C': 100,
'D': 500,
'M': 1000
}
total = 0
prev_value = 0
# Process from right to left to handle subtractive notation
for char in reversed(s):
cur_value = value_map[char]
if cur_value < prev_value:
total -= cur_value
else:
total += cur_value
prev_value = cur_value
return total