Permalink
Cannot retrieve contributors at this time
81 lines (69 sloc)
2.63 KB
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """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 |