Как починить конвертер из римских в арабские числа?

Рейтинг: 2Ответов: 2Опубликовано: 09.01.2023

Проблема лежит в прохождении по циклу (он начинается заново), вместо XC(90), находит X, a C вообще почему-то не ищет

rom2num = {'M': 1000, 'CM': 900, 'D': 500, 'CD': 400, 'C': 100,
           'XC': 90, 'XL': 40, 'X': 10, 'IX': 9, 'V': 5,
           'IV': 4, 'I': 1}

def tonum(str):
    num = 0
    while not str.find(""):
      for letter,value in rom2num.items():
          if letter in str:
              num+= value
              str = str.replace(letter,"",1)
    return num
        
print(tonum("MCMXCIV"))

Ответы

▲ 2Принят

while not str.find(""): - это видимо проверка строки на пустоту. Обычно пишут так: while str:. Это в точности означает "пока строка не пустая".

После правки в программе останется ошибка: 'CD' отобразится в 600. А должно быть 400. Проблема в том что сперва найдётся строка 'D' (500), а потом 'C' (100). В сумме 600. До строки 'CD' очередь не дойдет.

Последняя ошибка - 'L' пропущено в словаре.

Чтобы устранить ошибку "CD->600" нужно искать подстроку начиная с фиксированного места. Программа ниже разбирает строку слева направо, примеряя фрагменты из "словаря" к текущей позиции. Если фрагмент совпал, сумма увеличивается, текущая позиция двигается:

items = (
    ('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)
)


def to_n(roman):
    n = 0
    i = 0
    for t, v in items:
        # while t == roman[i:i + len(t)]:
        while roman.startswith(t, i):
            n += v
            i += len(t)
    return n
        

print(to_n(input()))
▲ 1

Зачем вы записали такое странное условие цикла not str.find("")? Вне зависимости от того, что у вас в строке, find всегда будет возвращать 0, даже если она пустая, поэтому у вас бесконечный цикл. Достаточно было проверить строчку на пустоту, например так: s == "".

А ещё код нерабочий по причине того, что в словаре сочетания из двух цифр идут за теми, которые состоят из одной цифры. Из-за этого, на примере CM ответ будет 1100, т.к. он сначала извлечёт M, потом C. Поэтому все двузначные цифры в словаре должны стоять впереди:

rom2num = {'CM': 900, 'CD': 400, 'XC': 90, 'XL': 40, 'IX': 9, 'IV': 4, 'M': 1000, 'D': 500, 'C': 100, 'L': 50, 'X': 10, 'V': 5, 'I': 1}

 def tonum(s):
  num = 0
  while s != "":
    for letter,value in rom2num.items():
        if letter in s:
            num+= value
            s = s.replace(letter,"",1)
  return num
        
print(tonum("MCMXCIV"))

Стоит сказать, что необязательно всегда items идут в том же порядке, что вы задали при инициализации словаря. В данном случае это порядок сохраняется, но не думайте, что он будет сохраняться и в других случаях.