# Roman numeral conversion

First time poster here…

I realize that rubyquiz.com is no longer really active, but some of the
code there is still used by people googling for example code (roman
numeral conversion in my case for a class I am taking), and I wanted to
point out that many of the solutions listed for quiz #22 are evaluating
roman to arabic numerals incorrectly.

If you run many of the solutions, especially the ones that use this
table:

``````    [ 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'  ]
]
``````

…and then you try to evaluate the string value XD (for example), it
will convert this string to 510. This should not happen; XD is not a
legal roman numeral, DX would be 510, and CDXC would be 490. The
problem seems to be that in roman to arabic numeral conversion, the
solutions just add the raw values together. This means that converters
using this kind of conversion will accept any combination of roman
numeral values from the table above…regardless of order.

A crazier example:

If you evaluate XIV, you get 14, by finding X and then IV in the table
above and then adding their corresponding values together.

If you put in IXIVI, it will also evaluate to 14 by adding IX + IV + I
and accept it as a valid roman numeral.

I don’t have a solution yet, but I thought I would at least point this
out in case someone is adding a to_roman method to Integer or something
and wants it to be 100% robust.

how about that one (it’s a little longish):

``````class String
def to_roman
str = self.downcase
raise SyntaxError, "Not a roman numeral" unless str =~
``````

/^[mdclxvi]+\$/
raise SyntaxError, “Not a roman numeral” if
%w{iiii vv xxxx ll cccc dd}.any? { |x| str.include?(x) }
str.tr!(“ivxlcdm”, “0123456”) # translate into numbers
level, last, deviated, ret = 7, 0, false, 0
table = [1,5,10,50,100,500,1000] # the translation table
str.each_char do |char|
num = char.to_i
if num > level # means a deviation
raise SyntaxError, “Not a roman numeral” if deviated
or
not # no double deviation
%w{01 02 23 24 45 46}.include?("#{last}#{num}")

only allowed deviations
ret -= table[last]*2 # remedy deviation
level = last-1 # don’t allow IXI or IXV etc.
deviated = true
else
deviated = false
level = num # don’t allow MLM etc.
end
ret += table[num]
last = num
end
ret
end
end

fulfills all your examples, but i dunno if it’s correct. would be great
if
someone
could test this (let alone improve it).

What it checks for:

• only [ivxlcdm] allowed
• ixc may each only occur max. 3 times in a row
• vld may each only occur max once in a row
• when dropping to a certain level, only the following sequences may
rise
above that level: cm cd xc xl ix iv
• and not twice in a row, so ixc is not legal
• and after that, the level drops to the smaller char, so ixivi is not
legal

…and then you try to evaluate the string value XD (for example), it

Cool, I will give this a shot, but while I know enough about Roman
numerals, I am not an expert by any means, so I will leave any
“approvals” to someone that knows everything about them :).

On Sep 18, 1:26 pm, Brian T. [email protected] wrote:

``````    [    5, 'V'  ],
``````

numeral values from the table above…regardless of order.
out in case someone is adding a to_roman method to Integer or something
and wants it to be 100% robust.

english/roman.rb checks out.

T.