Skip to content

Instantly share code, notes, and snippets.

@miguelff
Created October 6, 2013 00:39
Show Gist options
  • Save miguelff/6847802 to your computer and use it in GitHub Desktop.
Save miguelff/6847802 to your computer and use it in GitHub Desktop.
Roman numerals in python
#!/usr/bin/env python
# encoding: utf-8
"""
romans.py
Convert integer to roman numerals back and forth
Created by Miguel Fernández on 2013-10-06.
"""
class Romans:
@classmethod
def int(klass, roman):
return RomanToIntConverter(roman).convert()
@classmethod
def roman(klass, int):
return IntToRomanConverter(int).convert()
class IntRomanConverter:
UNITS = ['IX', 'VIII', 'VII', 'VI', 'V', 'IV', 'III', 'II', 'I']
TENS = ['XC', 'LXXX', 'LXX', 'LX', 'L', 'XL', 'XXX', 'XX', 'X']
HUNDREDS = ["CM","DCCC","DCC","DC","D","CD","CCC","CC","C"]
THOUSANDS = ["MMM","MM","M"]
def __init__(self, source):
self.source = source
def convert(self):
target = self.__emptyTarget()
rest = self.source
(rest, target) = self.__convertUnits(rest, target, self.THOUSANDS, 1000)
(rest, target) = self.__convertUnits(rest, target, self.HUNDREDS, 100)
(rest, target) = self.__convertUnits(rest, target, self.TENS, 10)
(rest, target) = self.__convertUnits(rest, target, self.UNITS, 1)
if (not self.__isValid(rest)):
self.__raiseError(self.source)
return target
class IntToRomanConverter(IntRomanConverter):
def __emptyTarget(self):
return ""
def __isValid(self, rest):
return rest == 0
def __raiseError(self, source):
raise Exception("Error: %d cannot be expressed as a roman" % source)
def __convertUnits(self, source, target, units, unitValue):
if (source > 0):
value = source / unitValue
index = len(units) - value
if (index >= 0 and index < len(units)):
romanChunk = units[index]
target += romanChunk
source -= value * unitValue
return (source, target)
class RomanToIntConverter(IntRomanConverter):
def __emptyTarget(self):
return 0
def __isValid(self, rest):
return len(rest) == 0
def __raiseError(self, source):
raise Exception("Error: %s cannot be expressed as an integer" % source)
def __convertUnits(self, source, target, units, unitValue):
for index, unit in enumerate(units):
if source.startswith(unit):
value = (len(units) - index) * unitValue
return (source.replace(unit,""), target + value)
return (source, target)
#!/usr/bin/env python
# encoding: utf-8
"""
romans_test.py
Tests Romans
Created by Miguel Fernández on 2013-10-06.
"""
from romans import Romans
import unittest
class RomanToInt(unittest.TestCase):
def testOne(self):
self.assertEquals(1, Romans.int("I"))
def testTwo(self):
self.assertEquals(2, Romans.int("II"))
def testFour(self):
self.assertEquals(4, Romans.int("IV"))
def testEight(self):
self.assertEquals(8, Romans.int("VIII"))
def testTen(self):
self.assertEquals(10, Romans.int("X"))
def testFifty(self):
self.assertEquals(50, Romans.int("L"))
def testSixtyNine(self):
self.assertEquals(69, Romans.int("LXIX"))
def testNinetyNine(self):
self.assertEquals(99, Romans.int("XCIX"))
def testOneHundred(self):
self.assertEquals(100, Romans.int("C"))
def testFiveHundred(self):
self.assertEquals(500, Romans.int("D"))
def testNineHundred(self):
self.assertEquals(999, Romans.int("CMXCIX"))
def testThreeThousand(self):
self.assertEquals(3000, Romans.int("MMM"))
def testThreeThousandAndOne(self):
self.assertEquals(3001, Romans.int("MMMI"))
def testThreeThousandAndSixtyNine(self):
self.assertEquals(3069, Romans.int("MMMLXIX"))
class IntoToRoman(unittest.TestCase):
def testOne(self):
self.assertEquals("I", Romans.roman(1))
def testNine(self):
self.assertEquals("IX", Romans.roman(9))
def testTen(self):
self.assertEquals("X", Romans.roman(10))
def testOneThousandAndNine(self):
self.assertEquals("MIX", Romans.roman(1009))
if __name__ == '__main__':
unittest.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment