Created
October 6, 2013 00:39
-
-
Save miguelff/6847802 to your computer and use it in GitHub Desktop.
Roman numerals in python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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