Если основной целью является уменьшение количества строк кода, можно сделать следующее.
Код
H = {"VI"=>" 4", "XI"=>" 9", "LX"=>" 40", "CX"=>" 90", "DC"=>" 400", "MC"=>" 900",
"I"=>" 1", "V"=>" 5", "X"=>" 10", "L"=>" 50", "C"=>" 100", "D"=>" 500", "M"=>" 1000"}
def roman_to_integer(roman_string)
roman_string.reverse.gsub(Regexp.union(H.keys), H).split.sum(&:to_i)
end
Примеры
%w| III LXIV CCXXVI CM CMXCVIII MDCCXII |.each {|s| puts "#{s}->#{ roman_to_integer(s)}"}
# III->3
# LXIV->64
# CCXXVI->226
# CM->900
# CMXCVIII->998
# MDCCXII->1712
Пояснение
Регулярные выражения анализируются слева направо, поэтому для использования одного из них нам нужно обратить roman_string
в качестве первого шага,Это означает, что мы также должны поменять местами ключи в хэше.
Это использует форму String # gsub , которая использует хэш в качестве аргумента.Обратите внимание, что ключи H
расположены в порядке убывания размера.Вот пример того, почему я это сделал.Предположим, указатель gsub
находится на "V"
, а следующий символ - "I"
.Порядок клавиш приведет к тому, что gsub
(что является жадным алгоритмом) будет соответствовать "VI"
, а не "V"
.
Для
roman_string = "CCXXVI"
шаги будут следующими.
k = H.keys
#=> ["VI", "XI", "LX", "CX", "DC", "MC", "I", "V", "X", "L", "C", "D", "M"]
r = Regexp.union(H.keys)
#=> /VI|XI|LX|CX|DC|MC|I|V|X|L|C|D|M/
t = s.gsub(r, H)
#=> " 1 5 10 10 100 100"
a = t.split
#=> ["1", "5", "10", "10", "100", "100"]
a.sum(&:to_i)
# => 226
Обратите внимание: если нам дано
ROMAN_TO_INT = { "I" => 1, "IV" => 4, "V" => 5, "IX" => 9, "X" => 10, "XL" => 40,
"L" => 50, "XC" => 90, "C" => 100, "CD" => 400, "D" => 500,
"CM" => 900, "M" => 1000 }
, мы можем вычислить H
следующим образом.
H = ROMAN_TO_INT.map { |k,v| [k.reverse, " #{v}"] }.sort_by { |k,_| -k.size }.to_h