All pastes #756517 Raw Edit

convert.py

public python v1 · immutable
#756517 ·published 2007-10-31 15:29 UTC
rendered paste body
#! /usr/bin/env python# -*- coding: utf-8 -*-# Time-stamp: "2007-10-11 00:27:04 sceptik"# Author: Alex A. Smirnov# This program is free software; you can redistribute it and/or# modify it under the terms of the GNU General Public License as# published by the Free Software Foundation; either version 2, or (at# your option) any later version.## This program is distributed in the hope that it will be useful, but# WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU# General Public License for more details.## You should have received a copy of the GNU General Public License# along with this program; if not, write the Free Software# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA# 02110-1301 USAfrom math import modfimport re## FIXME: сделать внятные сообщения об ошибках# NS matchesDECIMAL_MATCH = re.compile(r'^\d+$')DECIMAL2_MATCH = re.compile(r'^\w+(\.\w*)?$')ROMAN_MATCH = re.compile(r'^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$')BINARY_DECIMAL_MATCH = re.compile(r'^[0|1{0,3}|\.]+$')ALTERNATE_NUMERIC = {10: 'A', 11: 'B', 12: 'C', 13: 'D', 14: 'E', 15: 'F',                     16: 'G', 17: 'H', 18: 'I', 19: 'J', 20: 'K', 21: 'L',                      22: 'M', 23: 'N', 24: 'O', 25: 'P', 26: 'Q', 27: 'R',                      28: 'S', 29: 'T', 30: 'U', 31: 'V', 32: 'W', 33: 'X',                     34: 'Y', 35: 'Z'}RALTERNATE_NUMERIC = dict( zip(ALTERNATE_NUMERIC.values(),                                ALTERNATE_NUMERIC.keys()) )ROMAN_FUNDAMENTAL = (('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))DECIMAL_BINARY_EQ = {'0' : '0000', '1' : '0001', '2' : '0010', '3' : '0011',                      '4' : '0100', '5' : '0101', '6' : '0110', '7' : '0111',                      '8' : '1000', '9' : '1001', '.' : '.'}RDECIMAL_BINARY_EQ = dict( zip(DECIMAL_BINARY_EQ.values(),                                DECIMAL_BINARY_EQ.keys()) )class RomanOutOfBounds(Exception):    """ Raised when a numeral not a range from 0 to 4000."""    passclass NSValueError(Exception):    """ Raised when a bad numeral found."""    passdef dec2roman(number):    """ Dec -> Roman """        if not DECIMAL_MATCH.match( str(number) ):        raise NSValueError(number)    if not (0 < number < 4000):        raise RomanOutOfBounds(number)        result = ''    for roman, value in ROMAN_FUNDAMENTAL:        while number >= value:            number -= value            result += roman    return resultdef roman2dec(number):    """ Roman -> Dec """        if not ROMAN_MATCH.match(number):        raise NSValueError(number)        result = 0    index = 0            for roman, value in ROMAN_FUNDAMENTAL:        while number[ index:index + len(roman) ] == roman:            result += value            index += len(roman)    return resultdef dec2any(number, radix, accuracy=5):    """ Dec -> Any """        if not number:         return '0'    result = ''        fracp, intp = modf(number)    number = int(intp)            while number:        division = number % radix        number /= radix        result += (ALTERNATE_NUMERIC[division]                    if radix > 10 and division >= 10 else str(division))    result = result[::-1]        if fracp:        result += ('.' if result else '0.')                while fracp and accuracy:            accuracy -= 1                        fracp = fracp * radix            fracp, intp = modf(fracp)                        result += (ALTERNATE_NUMERIC[int(intp)]                        if radix > 10 and intp >= 10 else str(int(intp)))            return resultdef any2dec(number, radix):    """ Any -> Dec """    if not DECIMAL2_MATCH.match(number):        raise NSValueError, "any2dec: not a digit"    power = 0    result = 0        dotpos = number.find('.')    if dotpos > 0:        power = -len(number[dotpos + 1:])    for position in number[::-1]:                if position == '.':            continue                try:            value = int(position)            if value >= radix:                raise NSValueError(number)        except ValueError:            if radix > 10 and position in RALTERNATE_NUMERIC.keys() \                            and RALTERNATE_NUMERIC[position] < radix:                value = RALTERNATE_NUMERIC[position]            else:                raise NSValueError(number)        result += value * (radix ** power)        power += 1    return resultdef dec2bindec(number):    """ Decimal -> Binary-Decimal """        result = ''    for position in str(number):        result += DECIMAL_BINARY_EQ[position]            return resultdef bindec2dec(number):    """ Binary-Decimal -> Decimal """        if not number:         return 0    if not BINARY_DECIMAL_MATCH.search(number):        raise NSValueError(number)            parts  = str(number).split('.')    if len(parts) > 1:        parts[1] += ((4 - len(parts[1]) % 4) * '0'                      if len(parts[1]) % 4 else '')    parts[0] = ((4 - len(parts[0]) % 4) * '0'                 if len(parts[0]) % 4 else '') + parts[0]    results = []    for part in parts:        result = ''                for state in xrange(0, len(part) / 4):            try:                result += RDECIMAL_BINARY_EQ[part[state * 4:(state + 1) * 4]]            except KeyError:                raise NSValueError(number)                results += [result]            return '.'.join(results)