Welcome, guest | Sign In | My Account | Store | Cart

Provides two functions: romanToNumber - Converts a string of Roman Numerals (I,V,X,L,C,D,M) into an integer. (ignores formatting, will return best guess if improperly formatted) numberToRoman - Converts an integer into a string of Roman Numerals

Python, 123 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#Roman Numeral Converter
#Written By Brandon Martin
#Digital Sol

class IllegalCharacterError(Exception):
    pass

def romanToNumber(numerals):
    '''Converts a string of Roman Numerals (I,V,X,L,C,D,M) into an integer.'''

    romanConversionTable = {
        'I' : 1,
        'V' : 5,
        'X' : 10,
        'L' : 50,
        'C' : 100,
        'D' : 500,
        'M' : 1000
    }

    ### Build List of Numbers ###
    
    numberList = []
    for letter in numerals:
        # Build List of Numbers
        if letter in romanConversionTable:
            numberList += [romanConversionTable[letter]]
        else:
            raise IllegalCharacterError('{} is not a Roman Numeral'.format(letter))

    if len(numberList) == 1:
        return numberList[0]

    ### Construct Final Total ###

    previous = numberList[-1]
    total = previous
    for current in range(len(numberList)-2,-1, -1):
        if numberList[current] < previous:
            total -= numberList[current]
        else:
            total += numberList[current]
        previous = numberList[current]

    return total

def numberToRoman(integer):
    '''Converts an integer into a string of Roman Numerals.'''

    if type(integer) != int:
        raise TypeError('Input must be an integer.')
    
    numberConversionTable = {
        1 : 'I',
        5 : 'V',
        10 : 'X',
        50 : 'L',
        100 : 'C',
        500 : 'D',
        1000 : 'M'
    }
    quads = ('I','X','C')
    doubs = ('V','L','D')
    foundNumeral = ''
    found = 0

    ### Build List of Roman Numerals ###

    numeralList = []
    for value in [1000,500,100,50,10,5,1]:
        while integer >= value:
            integer -= value
            numeralList += [numberConversionTable[value]]
    if len(numeralList) == 1: #Return result if only one symbol
        return numeralList.pop()

    ### Modify List to Proper Formatting ###

    finalNumeralList = []
    repeats = 0

    for numeral in numeralList:
        if len(finalNumeralList) == 0:
            # ADD FIRST NUMBER
            finalNumeralList += [numeral]
        else:
            if numeral != finalNumeralList[len(finalNumeralList)-1]:
                # CURRENT NUMERAL IS DIFFERENT FROM THE LAST
                if 3 > repeats > 0:
                    # ADD IN ALL REPEATS
                    for i in range(repeats):
                        finalNumeralList += [finalNumeralList[-1]]
                repeats = 0
                finalNumeralList += [numeral]
            else:
                # CURRENT NUMERAL IS THE SAME AS THE LAST
                repeats += 1
                if repeats == 3 and numeral != 'M':
                    # EXCHANGE THREE ONES NUMERALS FOR ONE FIVES NUMERAL
                    modifiedNumeral = doubs[quads.index(numeral)]
                    if modifiedNumeral == finalNumeralList[len(finalNumeralList)-2]:
                        # NUMERALS IN A THREE DIGIT RANGE ADD TO 9
                        finalNumeralList.pop(len(finalNumeralList)-2)
                        if numeral != 'C':
                            finalNumeralList += [quads[quads.index(numeral)+1]]
                        else:
                            finalNumeralList += ['M']
                    else:
                        finalNumeralList += [modifiedNumeral]
                    repeats = 0
                elif numeral == 'M':
                    # AUTOMATICALLY ADD M
                    finalNumeralList += ['M']
                    repeats = 0
                    
    if repeats > 0:
        # ADD IN ANY REMAINING REPEATS
        for i in range(repeats):
            finalNumeralList += [finalNumeralList[-1]]
                        
    finalString = ''.join(finalNumeralList)
                                                        
    return finalString

The implementation I have coded seems a bit bulky to me, if anyone has a better method for accomplishing a task please let me know.

1 comment

Gary Whitsett 4 years, 10 months ago  # | flag

Hi Brandon,

Could this be simplified by adding the quads and doubs into the conversion table? In other words, include 4: "IV", 9: "IX", etc in the numberConversionTable. Then the "value in" statement includes all of them, as well ([1000,900,500,400,100,90,50,40,10,9,5,4,1]). This would make the code to find the triples redundant. Would this work or am I missing something?