mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 02:15:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			80 lines
		
	
	
	
		
			2.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			80 lines
		
	
	
	
		
			2.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """Convert to and from Roman numerals"""
 | |
| 
 | |
| __author__ = "Mark Pilgrim (f8dy@diveintopython.org)"
 | |
| __version__ = "1.4"
 | |
| __date__ = "8 August 2001"
 | |
| __copyright__ = """Copyright (c) 2001 Mark Pilgrim
 | |
| 
 | |
| This program is part of "Dive Into Python", a free Python tutorial for
 | |
| experienced programmers.  Visit http://diveintopython.org/ for the
 | |
| latest version.
 | |
| 
 | |
| This program is free software; you can redistribute it and/or modify
 | |
| it under the terms of the Python 2.1.1 license, available at
 | |
| http://www.python.org/2.1.1/license.html
 | |
| """
 | |
| 
 | |
| import re
 | |
| 
 | |
| #Define exceptions
 | |
| class RomanError(Exception): pass
 | |
| class OutOfRangeError(RomanError): pass
 | |
| class NotIntegerError(RomanError): pass
 | |
| class InvalidRomanNumeralError(RomanError): pass
 | |
| 
 | |
| #Define digit mapping
 | |
| 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))
 | |
| 
 | |
| def toRoman(n):
 | |
|     """convert integer to Roman numeral"""
 | |
|     if not (0 < n < 5000):
 | |
|         raise OutOfRangeError("number out of range (must be 1..4999)")
 | |
|     if int(n) != n:
 | |
|         raise NotIntegerError("decimals can not be converted")
 | |
| 
 | |
|     result = ""
 | |
|     for numeral, integer in romanNumeralMap:
 | |
|         while n >= integer:
 | |
|             result += numeral
 | |
|             n -= integer
 | |
|     return result
 | |
| 
 | |
| #Define pattern to detect valid Roman numerals
 | |
| romanNumeralPattern = re.compile("""
 | |
|     ^                   # beginning of string
 | |
|     M{0,4}              # thousands - 0 to 4 M's
 | |
|     (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
 | |
|                         #            or 500-800 (D, followed by 0 to 3 C's)
 | |
|     (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
 | |
|                         #        or 50-80 (L, followed by 0 to 3 X's)
 | |
|     (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
 | |
|                         #        or 5-8 (V, followed by 0 to 3 I's)
 | |
|     $                   # end of string
 | |
|     """ ,re.VERBOSE)
 | |
| 
 | |
| def fromRoman(s):
 | |
|     """convert Roman numeral to integer"""
 | |
|     if not s:
 | |
|         raise InvalidRomanNumeralError('Input can not be blank')
 | |
|     if not romanNumeralPattern.search(s):
 | |
|         raise InvalidRomanNumeralError('Invalid Roman numeral: %s' % s)
 | |
| 
 | |
|     result = 0
 | |
|     index = 0
 | |
|     for numeral, integer in romanNumeralMap:
 | |
|         while s[index:index+len(numeral)] == numeral:
 | |
|             result += integer
 | |
|             index += len(numeral)
 | |
|     return result
 | 
