Welcome, guest | Sign In | My Account | Store | Cart
###NUMTOOLS
###Written by Digital Sol

class UnknownKeyError(Exception):
    pass

class RangeError(Exception):
    pass

class FloatingPointError(Exception):
    pass

def isNumber(value):
    '''Return True if input is an integer or decimal number.'''
    value = str(value)
    decimal = False
    for i in value:
        if i == '.' and not decimal:
            decimal = True
        else:
            try:
                int(i)
            except:
                return False
    return True

def str_to_int(sentence, return_int=True):
    '''Returns spelled-out numbers as integers.
return_int: Return an integer rather than a string.'''
    
    number_conv_table = {

        'negative' : '0',
        '' : '0',
        'and' : '0',
        'dollars' : '0',
        'dollar' : '0',
        'zero' : '0',
        'one' : '1',
        'two' : '2',
        'three' : '3',
        'four' : '4',
        'five' : '5',
        'six' : '6',
        'seven' : '7',
        'eight' : '8',
        'nine' : '9',
        'ten' : '10',
        'eleven' : '11',
        'twelve' : '12',
        'thirteen' : '13',
        'fourteen' : '14',
        'fifteen' : '15',
        'sixteen' : '16',
        'seventeen' : '17',
        'eighteen' : '18',
        'nineteen' : '19',
        'twenty' : '20',
        'thirty' : '30',
        'forty' : '40',
        'fifty' : '50',
        'sixty' : '60',
        'seventy' : '70',
        'eighty' : '80',
        'ninety' : '90',
        'hundred' : '00', #sub flag
        'thousand' : '000', #flag
        'k' : '000', #flag
        'grand' : '000', #flag
        'million' : '000000', #flag
        'billion' : '000000000', #flag
        'trillion' : '000000000000', #flag
        'quadrillion' : '000000000000000', #flag
        'quintillion' : '000000000000000000', #flag
        'sextillion' : '000000000000000000000', #flag
        'septillion' : '000000000000000000000000', #flag
        'octillion' : '000000000000000000000000000', #flag
        'nonillion' : '000000000000000000000000000000', #flag
        'decillion' : '000000000000000000000000000000000', #flag
        'undecillion' : '000000000000000000000000000000000000', #flag
        'duodecillion' : '000000000000000000000000000000000000000', #flag
        'tredecillion' : '000000000000000000000000000000000000000000', #flag
        'quattuordecillion' : '000000000000000000000000000000000000000000000',
        }#flag

    flags = ['hundred', 'thousand', 'grand', 'million', 'billion', 'trillion',
             'quadrillion', 'quintillion','sextillion', 'septillion', 'octillion',
             'nonillion', 'decillion', 'undecillion', 'duodecillion', 'tredecillion',
             'quattuordecillion', 'k']
    sub_flags = ['hundred']

    output = 0
    section = 0
    sections = []
    hundred_flag = False #detected value 'hundred'
    negative_flag = False #detected value 'negative'
    currency_flag = False #detected value 'dollar'
    
    sentence = sentence.replace('-', ' ').split(' ') #allow spaces and hyphens
    lowered_sentence = []
    
    for i in sentence:
        lowered_sentence.append(i.lower())
        
    sentence = lowered_sentence #create list of words in lowercase

    for word in sentence:
        sum_flag = True

        if word in ['point', 'dot']:
            raise FloatingPointError('Sentence must represent an integer.')
        
        while True:
            try:
                number = number_conv_table[word]
                if word == 'negative': #detect negative
                    negative_flag = True
                if word in ['dollar', 'dollars', 'k']:
                    currency_flag = True
                    if return_int:
                        input('\nNOTICE: Currency will be represented as a string not an integer. *press enter*')
                        print()
                    return_int = False
                break
            except KeyError:
                ref = word
                print('\nWARNING:',word,'is not a valid key. Please replace it.')
                word = str(input('Modify word: '))
                print()

        if word in flags: #merge if word is a flagged word
            section = str(section)
            section += number
            if word in sub_flags: #do not yet append number
                hundred_flag = True
            
        else:
            section = int(section) + int(number)

        if word in flags and hundred_flag == False: #finalize section and append to list
            sections.append(int(section))
            section = 0

        hundred_flag = False #reset flag

    sections.append(int(section))

    output = sum(sections)

    if negative_flag:
        output = 0 - output

    if currency_flag:
        output = format(output,',d')
        return '$'+output

    if not return_int:
        return format(output,',d')

    else:
        return output

def int_to_str(number):
    '''Return integer as a spelled-out string.'''

    if not isNumber(number) and '-' not in str(number):
        raise ValueError('Input must be an integer')

    number = str(number)

    dollar_flag = False
    negative_flag = False

    while True:
        if number[0] == '$':
            dollar_flag = True
            number = number[1:]
        elif number[0] == '-':
            negative_flag = True
            number = number[1:]
        else:
            break

    number_conv_table = {

        '-' : 'negative',
        '$' : 'dollar',
        '0' : 'zero',
        '1' : 'one',
        '2' : 'two',
        '3' : 'three',
        '4' : 'four',
        '5' : 'five',
        '6' : 'six',
        '7' : 'seven',
        '8' : 'eight',
        '9' : 'nine',
        }

    number_conv_table_spec = {
        '0' : 'zero',
        '1' : 'zero',
        '2' : 'twenty',
        '3' : 'thirty',
        '4' : 'forty',
        '5' : 'fifty',
        '6' : 'sixty',
        '7' : 'seventy',
        '8' : 'eighty',
        '9' : 'ninety',
        }

    number_conv_table_ones = {
        '0' : 'ten',
        '1' : 'eleven',
        '2' : 'twelve',
        '3' : 'thirteen',
        '4' : 'fourteen',
        '5' : 'fifteen',
        '6' : 'sixteen',
        '7' : 'seventeen',
        '8' : 'eighteen',
        '9' : 'nineteen',
        }
    
    if str(number) in number_conv_table:
        if negative_flag:
            return 'negative '+number_conv_table[str(number)]
        else:
            return number_conv_table[str(number)]
    
    number = number[::-1]
    sectors = []

    for i in range(0, len(number), 3):
        sectors.append(number[i:i+3][::-1])

    sectors.reverse()

    flags = ['hundred', 'thousand', 'million', 'billion', 'trillion',
             'quadrillion', 'quintillion','sextillion', 'septillion', 'octillion',
             'nonillion', 'decillion', 'undecillion', 'duodecillion', 'tredecillion',
             'quattuordecillion']

    output = []
    word = ''
    hundred_flag = False
    and_flag = False
    tens_flag = False
    sector_place = len(sectors)

    if negative_flag:
        output.append('negative')

    for sector in sectors:
            
        hundred_flag = False
        
        if len(sector) == 3 and int(sector[0]) > 0:
            hundred_flag = True

        nums_place = len(sector)
        
        for num in sector:

            if nums_place == 1 and tens_flag:
                word = number_conv_table_ones[num]
                tens_flag = False

            elif nums_place == 2:
                
                if num == '1':
                    tens_flag = True
                else:
                    word = number_conv_table_spec[num]

            else:
                word = number_conv_table[num]

            if word != 'zero' and len(number) > 1 and not tens_flag:
                output.append(word)
                    
            if hundred_flag:
                output.append('hundred')
                hundred_flag = False

            if sector_place > 1 and nums_place == 1 and sector != '000':
                if (sector_place - 1) < 16:
                    output.append(flags[sector_place-1])
                else:
                    raise RangeError('Input number too large.')

            nums_place -= 1

        sector_place -= 1

    if dollar_flag:
        output.append('dollars')

    return ' '.join(output)

History