~ubuntu-branches/ubuntu/karmic/python-docutils/karmic

« back to all changes in this revision

Viewing changes to roman.py

  • Committer: Bazaar Package Importer
  • Author(s): martin f. krafft
  • Date: 2006-07-10 11:45:05 UTC
  • mfrom: (2.1.4 edgy)
  • Revision ID: james.westby@ubuntu.com-20060710114505-otkhqcslevewxmz5
Tags: 0.4-3
Added build dependency on python-central (closes: #377580).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""Convert to and from Roman numerals"""
2
 
 
3
 
__author__ = "Mark Pilgrim (f8dy@diveintopython.org)"
4
 
__version__ = "1.4"
5
 
__date__ = "8 August 2001"
6
 
__copyright__ = """Copyright (c) 2001 Mark Pilgrim
7
 
 
8
 
This program is part of "Dive Into Python", a free Python tutorial for
9
 
experienced programmers.  Visit http://diveintopython.org/ for the
10
 
latest version.
11
 
 
12
 
This program is free software; you can redistribute it and/or modify
13
 
it under the terms of the Python 2.1.1 license, available at
14
 
http://www.python.org/2.1.1/license.html
15
 
"""
16
 
 
17
 
import re
18
 
 
19
 
#Define exceptions
20
 
class RomanError(Exception): pass
21
 
class OutOfRangeError(RomanError): pass
22
 
class NotIntegerError(RomanError): pass
23
 
class InvalidRomanNumeralError(RomanError): pass
24
 
 
25
 
#Define digit mapping
26
 
romanNumeralMap = (('M',  1000),
27
 
                   ('CM', 900),
28
 
                   ('D',  500),
29
 
                   ('CD', 400),
30
 
                   ('C',  100),
31
 
                   ('XC', 90),
32
 
                   ('L',  50),
33
 
                   ('XL', 40),
34
 
                   ('X',  10),
35
 
                   ('IX', 9),
36
 
                   ('V',  5),
37
 
                   ('IV', 4),
38
 
                   ('I',  1))
39
 
 
40
 
def toRoman(n):
41
 
    """convert integer to Roman numeral"""
42
 
    if not (0 < n < 5000):
43
 
        raise OutOfRangeError, "number out of range (must be 1..4999)"
44
 
    if int(n) <> n:
45
 
        raise NotIntegerError, "decimals can not be converted"
46
 
 
47
 
    result = ""
48
 
    for numeral, integer in romanNumeralMap:
49
 
        while n >= integer:
50
 
            result += numeral
51
 
            n -= integer
52
 
    return result
53
 
 
54
 
#Define pattern to detect valid Roman numerals
55
 
romanNumeralPattern = re.compile('''
56
 
    ^                   # beginning of string
57
 
    M{0,4}              # thousands - 0 to 4 M's
58
 
    (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
59
 
                        #            or 500-800 (D, followed by 0 to 3 C's)
60
 
    (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
61
 
                        #        or 50-80 (L, followed by 0 to 3 X's)
62
 
    (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
63
 
                        #        or 5-8 (V, followed by 0 to 3 I's)
64
 
    $                   # end of string
65
 
    ''' ,re.VERBOSE)
66
 
 
67
 
def fromRoman(s):
68
 
    """convert Roman numeral to integer"""
69
 
    if not s:
70
 
        raise InvalidRomanNumeralError, 'Input can not be blank'
71
 
    if not romanNumeralPattern.search(s):
72
 
        raise InvalidRomanNumeralError, 'Invalid Roman numeral: %s' % s
73
 
 
74
 
    result = 0
75
 
    index = 0
76
 
    for numeral, integer in romanNumeralMap:
77
 
        while s[index:index+len(numeral)] == numeral:
78
 
            result += integer
79
 
            index += len(numeral)
80
 
    return result
81