#!/usr/bin/env python

#foolswood.co.uk 2012
#Python 2 and 3
#License LGPL

#Convert to or from roman numerals

numerals = ("M", "D", "C", "L", "X", "V", "I")
rn_vals = (1000, 500, 100, 50, 10, 5, 1)

n_numerals = len(numerals)
numiter = range(n_numerals)

def from_rn(string):
	'''Convert from a numeral string to an integer'''
	#Input sanitization
	string = string.upper()
	count_numerals = 0
	for n in numerals:
		count_numerals += string.count(n)
	if count_numerals != len(string): #ensure string contains only numerals
		return None
	#Convert recursively
	def convert(string):
		for n in numiter:
			index = string.find(numerals[n])
			if index == -1: #numeral does not occur
				continue
			else: #highest present numeral
				#split and recurse
				rval = rn_vals[n]
				if index != 0:
					rval -= convert(string[:index])
				if index+1 < len(string):
					rval += convert(string[index+1:])
				return rval
	return convert(string)

def to_rn(integer):
	'''Convert from an integer to a numeral string'''
	result = ""
	for n in numiter:
		#take as many multiples of the largest possible letter as is nessacary
		while integer >= rn_vals[n]:
			result += numerals[n]
			integer -= rn_vals[n]
		#see if the remainder can be expressed as a subtraction from the current largest letter
		for m in range(n_numerals-1, n, -1): #check smallest first
			if integer >= rn_vals[n] - rn_vals[m] and rn_vals[n] != 2*rn_vals[m]:
				result += numerals[m] + numerals[n]
				integer -= rn_vals[n] - rn_vals[m]
	return result
