Возможно, было бы лучше представить значения в виде списка кортежей, поскольку это позволяет нам определять в них порядок , и поэтому мы можем избежать совпадения 'I'
в случае, если строка содержит при этомточка 'IX'
.Таким образом, мы можем определить преобразование как:
roman_numerals = [
('M', 1000),
('CM', 900),
('D', 500),
('CD', 400),
('C', 100),
('XC', 90),
('L', 50),
('XL', 40),
('X', 10),
('IX', 9),
('V', 5),
('IV', 4),
('I', 1)
]
Обратите внимание, что вы забыли использовать IX
, это делает его в некоторой степени проблематичным, поскольку оно будет интерпретировать IX
как 11
.
Теперь мы можем обрабатывать строку, каждый раз выполняя проверку str.startswith()
[Python-doc] , и с того момента, как мы нашли префикс, добавляем соответствующее значение,и увеличиваем смещение строки, например:
def roman_int(user_choice):
ix = 0
result = 0
while ix < len(user_choice):
for k, v in roman_numerals:
if user_choice.startswith(k, ix):
result += v
ix += len(k)
break
else:
raise ValueError('Invalid Roman number.')
return result
. Таким образом, мы перечисляем строку и каждый раз ищем совпадения с римской цифрой.Например:
>>> roman_int('MCMXC')
1990
>>> roman_int('MCMXCIII')
1993
>>> roman_int('MMXVIII')
2018
Система также выдаст ошибку, если, например, мы введем недопустимые символы:
>>> roman_int('MMXQVIII')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in roman_int
ValueError: Invalid Roman number.
Вышеупомянутое, однако, не очень эффективно: каждый раз, когда мы перечисляем roman_literals
домы находим совпадение.Но как только мы обрабатываем «пятидесятые» (L
), мы знаем, что никогда больше не будем разбирать «тысячи» (M
).Мы можем повысить производительность, запомнив индекс в roman_numerals
:
def roman_int(user_choice):
ix = 0
iy = 0
result = 0
while ix < len(user_choice):
while iy < len(roman_numerals) and not user_choice.startswith(roman_numerals[iy][0], ix):
iy += 1
if iy < len(roman_numerals):
result += roman_numerals[iy][1]
ix += len(roman_numerals[iy][0])
else:
raise ValueError('Invalid Roman numeral')
return result
Это снова дает ожидаемые результаты:
>>> roman_int('MDCCLXXVI')
1776
>>> roman_int('MCMLIV')
1954
>>> roman_int('MCMXC')
1990
>>> roman_int('MMXIV')
2014
>>> roman_int('MMXVIII')
2018
Но также более строгое, например CMM
не действительная римская цифра, тогда как MCM
:
>>> roman_int('CMM')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 12, in roman_int
ValueError: Invalid Roman numeral
>>> roman_int('MCM')
1900