Szerkesztő:BinBot/roman.py

#coding: utf-8
"""
This will translate Hindu-Arabic numbers to Romans and back in range 1-3999.
Arabic input may be either a number or a string; if it has a valid int()
value, it will be transformed to Roman. Otherwise the input will be treated
as a Roman number and the appropriate Arabic number will be returned.
The result is in .result. 

"Lower case Roman numbers" (such as "viii") are not accepted for the sake
of clarity. You have to explicitly apply .upper() to them first. No "free-
style" Roman numbers like "IC" or "IIII" will be handled.

The module has a romanlist function, which returns a list of Roman numbers
in the given range. Note that range has to have a beginning as well as an
end (anyhow, the default beginning 0 would be incorrect for transforming).

In silent mode (default) Arabic numerals outside of the given range will give
an empty string and invalid Roman numbers or other strings give zero.
If you directly specify the mode as "strict" (or any other value different
from 'silent'), ValueError will be raised for errors.

You don't have to explicitly instantiate this class as a variable. Examples:
_____________________________________________________________________________
             Instruction                   |           Result
print roman.roman(3999).result             | MMMCMXCIX
print roman.roman('43').result             | XLIII
print roman.roman('4300').result           | '' (empty string; out of range)
print roman.roman('4300','strict').result  | ValueError
print roman.roman('MMXI').result           | 2011
print roman.roman('cix').result            | 0 (invalid)
print roman.roman('cix'.upper()).result    | 109
print roman.roman('MMXIC').result          | 0 (invalid)
print roman.roman('MMXIC','strict').result | ValueError
print roman.romanlist(5,10)                | ['V', 'VI', 'VII', 'VIII', 'IX']
print roman.romanlist(5,4011,1)            | ValueError
_____________________________________________________________________________


"""
#
# (C) Bináris (http://hu.wikipedia.org/wiki/user:Bin%C3%A1ris), 2011
#
# Distributed under the terms of the MIT license.
#
import string

class roman(object):
    def __init__(self, value, mode='silent'):
        self.ones = ['','I','II','III','IV','V','VI','VII','VIII','IX']
        self.tens = [self.ones[i].translate(string.maketrans('IVX','XLC')) for i in range(10)]
        self.hundreds = [self.ones[i].translate(string.maketrans('IVX','CDM')) for i in range(10)]
        self.thousands = ['','M','MM','MMM']
        self.ranges = {
            'I': [(1,5),(9,10)],
            'V': [(5,9)],
            'X': [(10,50),(90,100)],
            'L': [(50,90)],
            'C': [(100,500),(900,1000)],
            'D': [(500,900)],
            'M': [(1000,4000)],
        }
        self.mode = mode
        try:
            self.value = int(value)
        except ValueError:
            self.value = value
            self.result = self.unroman(self.value)
        else:
            self.result = self.roman(self.value)
            #Must be in else clause, otherwise its own ValueError would be caught.
    
    def roman(self,i):
        if i in range(1,4000):
            return self.thousands[i/1000] + self.hundreds[(i % 1000)/100] \
                + self.tens[(i % 100)/10] + self.ones[i % 10]
        elif self.mode == 'silent':
            return ''
        else:
            raise ValueError, "number has to be between 1 and 3999."

    def error(self):
        if self.mode == 'silent':
            return 0
        else:
            raise ValueError, "this is not a valid Roman number."

    def unroman(self,s):
        if s == '' or s[0] not in self.ranges:
            return self.error()
        for r in self.ranges[s[0]]:
            for i in range(r[0],r[1]):
                if self.roman(i) == s:
                    return i
        return self.error()

def romanlist(i,j,mode='silent'):
    return [roman(x,mode).result for x in range(i,j)]

if __name__ == "__main__":
    print "This module will not run directly, import it. See the code for help."