# Roman Numerals (Python)

Updated 0 Tallied Votes 3K Views

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
# 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
"""``````

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

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

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

``````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

@@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

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:
arabic += roman_to_decimal[roman[len(roman)-1]]

print "\nThe roman numeral", roman, "is equal to",arabic``````

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

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

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

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!
"""``````

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.