module RomanNumeral
#--
# Numerals
#++
I = 1
V = 5
X = 10
L = 50
C = 100
D = 500
M = 1000
##
# Parse roman numerals where _val_
# may be Numeric, a string consisting of
# digits, or roman numerals.
def self.parse val
return val if Numeric === val
return val.to_i if val =~ /\A\d+\Z/
val.scan(/[IVXLCDM]/).inject(0) do |sum, numeral|
sum + const_get(numeral)
end
end
end
p RomanNumeral.parse('12')
p RomanNumeral.parse('II')
p RomanNumeral.parse('IV')
p RomanNumeral.parse('X')
p RomanNumeral.parse(1)
p RomanNumeral.parse(1.5)
Refactorings
No refactoring yet !
steved
October 16, 2009, October 16, 2009 19:59, permalink
Your parse method doesn't take into account that when a Roman numeral is is followed by a larger-valued numeral that its value should be subtracted from the following numeral's value.
Running your code shoes 'IV' returns 6 rather than 4.
Colin Curtin
October 16, 2009, October 16, 2009 20:34, permalink
IV is 4, though, not 6.
module RomanNumeral
ROMAN_ELMS = DATA.readlines.map do |elem|
r, a = elem.split(/\s+/)
[r, a.to_i]
end
def self.parse(val)
return val if Numeric === val
return val.to_i if val =~ /\A\d+\Z/
index = 0
total = 0
while index < val.size
key = ROMAN_ELMS.find{|r, a| val[index..(index + r.size-1)] == r}
index += key.first.size
total += key.last
end
total
end
end
p RomanNumeral.parse('12')
p RomanNumeral.parse('II') # 2
p RomanNumeral.parse('IV') # 4
p RomanNumeral.parse('X') # 10
p RomanNumeral.parse('MMDCLXXXIV') # 2684
p RomanNumeral.parse(1)
p RomanNumeral.parse(1.5)
__END__
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
Tj Holowaychuk
October 16, 2009, October 16, 2009 22:05, permalink
oh.. fuck.. haha I should have ... actually known that first I suppose :P
little parser. I am working with strings that may or may not be roman numerals, so to prevent a bunch of cruft we pass through regular numerical values