john pfeiffer
  • Home
  • Categories
  • Tags
  • Archives

unittest roman.py

'''
Convert to and from Roman numerals
2012-12-21
@author: John
'''

__author__ = "johnpfeiffer"
__version__ = "$Revision: 1.2 $"
__date__ = "$Date: 2012-12-21 $"

import re


class RomanError( Exception ): pass
class OutOfRangeError( RomanError ): pass
class NotIntegerError( RomanError ): pass
class InvalidRomanNumeralError( RomanError ): pass


MAX_ROMAN_NUMERAL = 4999


romanNumeralMap = ( ( '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 ) )

# Create tables for fast conversion of roman numerals.
# See fillLookupTables() below.
toRomanTable = [ None ]  # Skip an index since Roman numerals have no zero
fromRomanTable = {}

def toRoman( n ):
    """convert integer to Roman numeral"""
    if not ( 0 < n <= MAX_ROMAN_NUMERAL ):
        raise OutOfRangeError, "number out of range (must be 1..4999)"
    if int( n ) <> n:
        raise NotIntegerError, "non-integers can not be converted"
    return toRomanTable[n]

def fromRoman( s ):
    """convert Roman numeral to integer"""
    if not s:
        raise InvalidRomanNumeralError, 'Input can not be blank'
    if not fromRomanTable.has_key( s ):
        raise InvalidRomanNumeralError, 'Invalid Roman numeral: %s' % s
    return fromRomanTable[s]

def toRomanDynamic( n ):
    """convert integer to Roman numeral using dynamic programming"""
    assert( 0 < n <= MAX_ROMAN_NUMERAL )
    assert( int( n ) == n )
    result = ""
    for numeral, integer in romanNumeralMap:
        if n >= integer:
            result = numeral
            n -= integer
            break
    if n > 0:
        result += toRomanTable[n]
    return result

def fillLookupTables():
    """compute all the possible roman numerals"""
    # Save the values in two global tables to convert to and from integers.
    for integer in range( 1, MAX_ROMAN_NUMERAL + 1 ):
        romanNumber = toRomanDynamic( integer )
        toRomanTable.append( romanNumber )
        fromRomanTable[romanNumber] = integer

fillLookupTables()

  • « project package modules classes unit tests
  • unittest romantest assertRaises »

Published

Dec 21, 2012

Category

python

~236 words

Tags

  • python 180
  • roman.py 1
  • unittest 12