From: Fabian Streitel Date: 2009-09-19T05:10:19+09:00 Subject: Re: Roman numeral conversion --00504502d48e72e6750473dfb830 Content-Type: text/plain; charset=ISO-8859-1 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 > 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. > > --00504502d48e72e6750473dfb830--