Browse | Submit A New Snippet | Create A Package

## Roman Numerals

Type:
Class
Category:
Math Functions
Language:
Ruby

Description:
Completely pointless class that converts integers to Roman numerals and vice versa, also extends the integer class with a "to_roman" method. Using method missing as syntactic sugar for converting numerals to numbers.

### Versions Of This Snippet::

 Snippet ID Download Version Date Posted Author Delete 186 1.0 2006-11-18 22:11

## Latest Snippet Version: :1.0

```##########################################################
# Roman Numeral converter -- By Sam Kellett
#
# Examples:
# r = Roman.new
# r.to_int "viii" # 8
# r.to_int "mcmxcix" # 1999
# r.viii # 8
# r.mcmxcix # 1999
# r.to_roman 2550 # "mmdl"
# r.to_roman 9 # "ix"
# 2550.to_roman # "mmdl"
#
# Supports:
#  Rules regarding Roman numerals often state that a symbol representing 10x may not
#  precede any symbol larger than 10x+1. For example, C cannot be preceded by I or V,
#  only by X (or, of course, by a symbol representing a value equal to or larger than
#  C). Thus, one should represent the number "ninety-nine" as XCIX, not as the
#  "shortcut" IC.
#    -- Wikipedia (http://en.wikipedia.org/wiki/Roman_numerals#XCIX_or_IC.3F)
#
#
# To-do:
#  - Basic arithmetic with roman numerals
#  - Integration with the Time and Date objects

class Roman
VALUES = ["i", "v", "x", "l", "c", "d", "m"]
NUMERAL = {
"i" => 1,
"v" => 5,
"x" => 10,
"l" => 50,
"c" => 100,
"d" => 500,
"m" => 1000
}
SHORTCUTS = {
"cm" => "dcccc",
"ld" => "ccccl",
"xc" => "lxxxx",
"vl" => "xxxxv",
"ix" => "viiii",
"iv" => "iiii"
}
def to_int(str)
total = 0
str.downcase!
return unless str =~ /^[mcdlxvi]+\$/

str.gsub! Regexp.compile(SHORTCUTS.keys.join("|")) do
SHORTCUTS[\$&]
end

str.split("").each do |char|
total += NUMERAL[char]
end
total
end

def to_roman(int)
numbers = reverse_hash NUMERAL
longcuts = reverse_hash SHORTCUTS
#return "bad" unless int =~ /^[0-9]+\$/
roman = ""

mknum = []
remainder = int.to_i
numbers.keys.sort.reverse.each do |num|
tmp = remainder.divmod num
mknum.push tmp[0]
remainder = tmp[1]
end
values = VALUES.reverse
mknum.each_with_index do |num, i|
roman << values[i]*num
end
roman.gsub! Regexp.compile(longcuts.keys.join("|")) do
longcuts[\$&]
end
roman
end

private
def reverse_hash(hsh)
tmp = {}
hsh.each do |key, value|
tmp[value] = key
end
tmp
end
def method_missing(method_id)
to_int(method_id.id2name)
end
end

class Integer
def to_roman
r = Roman.new
r.to_roman(self)
end
end
```

### Submit a new version

You can submit a new version of this snippet if you have modified it and you feel it is appropriate to share with others..