Roman Numerals (Python)

Updated vegaseat 0 Tallied Votes 3K Views Share

Let Python do the work for you and figure out the roman numerals for a given integer. I have to ask you to keep the integer values somewhat reasonably low (from 1 to 4999), since roman numerals from 5000 on use characters with an overline and most PCs don't have those in the character set.

# convert an integer to a roman numeral
# keep it reasonable since from 5000 on special characters are used
# see also: http://en.wikipedia.org/wiki/Roman_numerals
# tested with Python24       vegaseat        25jan2007

def int2roman(number):
    numerals = { 1 : "I", 4 : "IV", 5 : "V", 9 : "IX", 10 : "X", 40 : "XL", 
        50 : "L", 90 : "XC", 100 : "C", 400 : "CD", 500 : "D", 900 : "CM", 1000 : "M" }
    result = ""
    for value, numeral in sorted(numerals.items(), reverse=True):
        while number >= value:
            result += numeral
            number -= value
    return result

print int2roman(input("Enter an integer (1 to 4999): "))

"""
Enter an integer (1 to 4999): 2007
MMVII
"""
pythonuser18 0 Newbie Poster

i'm just playing around with python and decided to try this code out but keep getting a syntax error pointing to the colon after the 1 in,

Gribouillis 1,391 Programming Explorer Team Colleague

I just tested it with python 2.6 and it works. For python 3.1, I had to change the last statement to

print(int2roman(int(input("Enter an integer (1 to 4999): "))))

and it works.

vegaseat 1,735 DaniWeb's Hypocrite Team Colleague

@pythonuser18
you used () instead of {}
a dictionary container needs the curly braces.

pythonuser18 0 Newbie Poster
def DecToRom (number) :
    numerals={1: "I", 4: "IV", 5: "V", 9: "IX", 10: "X", 40: "XL", 50: "L", 90: "XC", 100: "C", 400: "CD", 500: "D", 900: "CM", 1000: "M"}
    result=""
    for value, numeral in sorted(numerals.items(), reverse=True):
        while number >= value:
            result += numeral
            number -= value
    return result
print DecToRom(raw_input(“Decimal number: “))

could someone tell me why this isn't working? It says Syntax Error: invalid syntax

I know the indents aren't formatted correctly on this post, but they are as they are suppose to be in python

Gribouillis 1,391 Programming Explorer Team Colleague

@@pythonuser18 For reference, I got it working, with python 2.6 and this last line:

print DecToRom(int(raw_input("Decimal number: ")))
pythonuser18 commented: Thanks a million! +0
woooee 814 Nearly a Posting Maven

Roman to integer. Note that it will take something like XXIXV and convert it. If someone already has a routine to check for valid input, please post it. And I'm afraid we've just eliminated one standard homework question. Oh well, nothing lasts forever.

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

roman = raw_input("Enter the roman numeral to convert to arabic: ").upper()

converted = True
arabic = 0
for n in range(0, len(roman)-1):
    this_char = roman[n]
    next_char = roman[n+1]
    if (this_char in roman_to_decimal) and \
       (next_char in roman_to_decimal):

        this_number = roman_to_decimal[this_char]
        next_number =  roman_to_decimal[next_char]
        print "converting %s to %d....." % (this_char, this_number),
        if this_number < next_number:
            arabic -= this_number
        else:
            arabic += this_number
        print "Total now =", arabic

    else:
        print "\nthis chr (%s) or next chr (%s) is not a valid roman numeral" \
              % (this_char, next_char)
        converted = False
        break

if converted:
    ##  add last roman numeral
    arabic += roman_to_decimal[roman[len(roman)-1]]

    print "\nThe roman numeral", roman, "is equal to",arabic
eljakim 0 Newbie Poster

A quick solution that does both directions:

# Roman Numerals
# 2010-06-15, Eljakim Schrijvers

mapping = [ ('cd','cccc'), ('xl','xxxx'),('iv','iiii'),('d','ccccc'),('l','xxxxx'),('v','iiiii'), ('cm','ccccccccc'), ('xc','xxxxxxxxx'),('ix','iiiiiiiii')]
mapping.reverse()
bignums = [ ('m',1000), ('c',100), ('x', 10), ('i',1) ]

def fromroman(x):
	for (kort, lang) in mapping: x= x.replace(kort, lang)
	x = '+'.join(list(x))
	for (karakter, waarde) in bignums: x = x.replace(karakter, str(waarde))
	if x=='': x = '0'
	return eval(x)

def toroman(x):
	val = ''
	for (karakter, waarde) in bignums:
		val = val + (x / waarde) * karakter
		x = x % waarde
	for (kort, lang) in mapping: 
		val = val.replace(lang,kort)
	return val
TrustyTony 888 ex-Moderator Team Colleague Featured Poster

Nice concept but fails in execution:

# Roman Numerals
# 2010-06-15, Eljakim Schrijvers

# bug testing, translation of variables and reformating
# Tony Veijalainen 2010-06-16

mapping = [ ('cd','cccc'),
            ('xl','xxxx'),
            ('iv','iiii'),
            ('d','ccccc'),
            ('l','xxxxx'),
            ('v','iiiii'),
            ('cm','ccccccccc'),
            ('xc','xxxxxxxxx'),
            ('ix','iiiiiiiii')]


mapping.reverse()
bignums = [ ('m',1000), ('c',100), ('x', 10), ('i',1) ]

def fromroman(x):
	for (shortv, longv) in mapping: x= x.replace(shortv, longv)
	x = '+'.join(list(x))
	for (character, word) in bignums: x = x.replace(character, str(word))
	if x=='': x = '0'
	return eval(x)

def toroman(x):
	val = ''
	for (character, word) in bignums:
		val = val + (x / word) * character
		x = x % word
	for (shortv, longv) in mapping: 
		val = val.replace(longv,shortv)
	return val

for i in range(5000):
    if fromroman(toroman(i)) != i:
        print ('Bug found: %i, %s, %s' % (i,toroman(i),fromroman(toroman(i))))

The code gives plenty of bugs printed.

TrustyTony 888 ex-Moderator Team Colleague Featured Poster

Got it passing my test by rearranging the values that were present in bug cases in the mapping (cleaned up multiletter expressions by *):

# Roman Numerals
# 2010-06-15, Eljakim Schrijvers

# bug testing, translation of variables and reformating
# Tony Veijalainen 2010-06-16

mapping = [ ('d',5*'c'),
            ('l',5*'x'),
            ('v',5*'i'),
            ('cm',9*'c'),
            ('xc',9*'x'),
            ('ix',9*'i'),
            ('cd',4*'c'),
            ('iv',4*'i'),
            ('xl',4*'x')]


mapping.reverse()
bignums = [ ('m',1000), ('c',100), ('x', 10), ('i',1) ]

def fromroman(x):
	for (shortv, longv) in mapping: x= x.replace(shortv, longv)
	x = '+'.join(list(x))
	for (character, word) in bignums: x = x.replace(character, str(word))
	if x=='': x = '0'
	return eval(x)

def toroman(x):
	val = ''
	for (character, word) in bignums:
		val = val + (x / word) * character
		x = x % word
	for (shortv, longv) in mapping: 
		val = val.replace(longv,shortv)
	return val

bugs=0
for i in range(5000):
    if fromroman(toroman(i)) != i:
        print ('Bug found: %i, %s, %s' % (i,toroman(i),fromroman(toroman(i))))
        bugs+=1

print(('Number of bugs found: %i' % bugs) if bugs else 'Test passed!')


""" Output:
Test passed!
"""
vegaseat commented: sharp mind +11
TrustyTony 888 ex-Moderator Team Colleague Featured Poster

Correct fix is take out permanent reverse and use reversed() in to roman translation:

# Roman Numerals
# 2010-06-15, Eljakim Schrijvers

mapping = [ ('cd',4*'c'),
            ('xl',4*'x'),
            ('iv',4*'i'),
            ('d',5*'c'),
            ('l',5*'x'),
            ('v',5*'i'),
            ('cm',9*'c'),
            ('xc',9*'x'),
            ('ix',9*'i')]

bignums = [ ('m',1000), ('c',100), ('x', 10), ('i',1) ]

## vegaseat function for error check
def int2roman(number):
    numerals = { 1 : "I", 4 : "IV", 5 : "V", 9 : "IX", 10 : "X", 40 : "XL", 
        50 : "L", 90 : "XC", 100 : "C", 400 : "CD", 500 : "D", 900 : "CM", 1000 : "M" }
    result = ""
    for value, numeral in sorted(numerals.items(), reverse=True):
        while number >= value:
            result += numeral
            number -= value
    return result

def fromroman(x):
	for (shortv, longv) in mapping: x= x.replace(shortv, longv) ## reverse order needed
	x = '+'.join(list(x))
	for (character, word) in bignums: x = x.replace(character, str(word))
	if x=='': x = '0'
	return eval(x)

def toroman(x):
	val = ''
	for (character, word) in bignums:
		val = val + (x / word) * character
		x = x % word
	for (shortv, longv) in reversed(mapping): ## reverse here not permanantly
		val = val.replace(longv,shortv)
	return val

bugs1 = bugs2 = 0
for i in range(5000):
    if fromroman(toroman(i)) != i:
        print ('Reverse failure: %i, %s, %s' % (i,toroman(i),fromroman(toroman(i))))
        bugs1+=1

    if  int2roman(i).lower() != toroman(i): 
        print ('Wrong roman: %i, %s, %s' % (i,int2roman(i),toroman(i)))
        bugs2+=1

print(('Number of bugs found: %i reverse failure, %i wrong roman' % (bugs1,bugs2) if bugs1 + bugs2 else 'Test passed!'))
""" Last ilne of output:
Test passed!
"""
eljakim 0 Newbie Poster

I am quite embarrassed at the low quality I produced in the middle of the night.

Thank you for fixing it.

Eljakim

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.