summaryrefslogtreecommitdiffstats
path: root/Doc/tools
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2007-08-16 23:48:43 (GMT)
committerGuido van Rossum <guido@python.org>2007-08-16 23:48:43 (GMT)
commitaf554a0e17ceb0e6a3cc0c07e9cf6db2f80c1ad9 (patch)
tree7719b2787d82dd1cc7afad76ad989fc9b1f1504f /Doc/tools
parent10c17ba299513184e39c85fc5c3ecaf2fd13187e (diff)
downloadcpython-af554a0e17ceb0e6a3cc0c07e9cf6db2f80c1ad9.zip
cpython-af554a0e17ceb0e6a3cc0c07e9cf6db2f80c1ad9.tar.gz
cpython-af554a0e17ceb0e6a3cc0c07e9cf6db2f80c1ad9.tar.bz2
First merge from the trunk straight into the py3k branch. I'm not
using the message generated by svnmerge, because it contains a lot of stuff about the Doc tree, which I'm not merging this time due to the way the Doc tree was initially added. I am however adding roman.py which was added later to Doc/tools. I'll try to diff the two Doc trees separately to see if there's stuff I missed.
Diffstat (limited to 'Doc/tools')
-rw-r--r--Doc/tools/roman.py80
1 files changed, 80 insertions, 0 deletions
diff --git a/Doc/tools/roman.py b/Doc/tools/roman.py
new file mode 100644
index 0000000..33f6db7
--- /dev/null
+++ b/Doc/tools/roman.py
@@ -0,0 +1,80 @@
+"""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