[Tutor] please return flys in ointment

Dave Angel davea at davea.name
Sun Jul 7 07:30:39 CEST 2013


On 07/06/2013 10:40 PM, Jim Mooney wrote:
> On 6 July 2013 19:09, Dave Angel <davea at davea.name> wrote:
>>
            <SNIP>
>
>> If you'd like, I'll post my full version, changed as little as possible from
>
> That would be helpful. The corrections are already four times the size
> of the program, and at least three pots of coffee ;')
>

I hope this is useful.  There are lots more places where I might clean 
things up, but I wanted to make it as close to yours as possible, so you 
could reasonably diff the two.

# Using C:\Python33\python.exe on Win 7 in c:\python33\jimprogs - not
#Windows-specific
# Also works with python 2.7


import sys
import random


#No need to check version, just try to use raw_input.  If it's not defined,
#  then input should already work
try:
     input = raw_input
except NameError as e:
     pass      #we must be on version 3.0 or larger

try:
     range = xrange
except NameError as e:
     pass  #we must be on version 3.0 or larger

# Data
ones = {'1': 'one', '2': 'two', '3': 'three', '4': 'four', '5': 'five',
'6': 'six',
'7': 'seven', '8': 'eight', '9': 'nine'}

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

doubles = {'0': 'ten', '1': 'eleven', '2': 'twelve', '3': 'thirteen', '4':
'fourteen',
'5': 'fifteen', '6': 'sixteen', '7': 'seventeen', '8': 'eighteen', '9':
'nineteen'}

powers_of_1000 = (' thousand', ' million', ' billion', ' trillion',
' quadrillion', ' quintillion', ' sextillion', ' septillion', ' octillion',
' nonillion', ' decillion')

'''add these later, and also option for dollars-and-cents ending.
'vigintillion', 'novemdecillion', 'octodecillion', 'septendecillion',
'sexdecillion', 'quindecillion', 'quattuordecillion', 'tredecillion',
'duodecillion', 'undecillion',
'decillion', 'nonillion'
'''

# Functions
def get_raw_input():
     '''Enter a positive integer. A list of triplets in the same order will
be returned.
     Raise ValueError to loop on non-integer input, or return 'zero'
trigger-value of
     'xxx' if all zeroes are entered. If input is okay, strip leading
zeroes, then
     zero-pad leftmost triplet to three characters, so all slices are
triplets. Adjust
     input for different Python versions.'''
     while True:
         try:
             if sys.version[0:3] == '2.7':
                 numbers_str = original = raw_input('Enter a positive 
integer, space \
separated if desired.')
             elif sys.version[0:3] == '3.3':
                 numbers_str = original = input('Enter a positive 
integer, space \
separated if desired.')
             else:
                 print('Python versions 2.7 and 3.3 only supported')
                 sys.exit()

             numbers_str = ''.join(numbers_str.split())
             if numbers_str == '' or numbers_str == ' ': raise ValueError

             #NO POINT in special-casing zero.  It's a perfectly valid 
value.
             #numbers_int = int(numbers_str)
             #if numbers_int == 0:
             #    print('Zero')
             #    sys.exit()

             numbers_str = str(int(numbers_str)) #normalize it
             if len(numbers_str) > 36: raise ArithmeticError
             break
         except KeyboardInterrupt:
             print('Program cancelled by user')
             sys.exit()
         except ValueError as err:
             print(original, "is not an integer.")
             continue
         except ArithmeticError as err:
             print(original, "is too big.\n999...decillion is max: 
10**37-1 or 36 chars \
or 12 groups of 3 chars")
     return numbers_str

def make_triplets_from_input(numbers_str):
     leftpad = "0" * ((-len(numbers_str))%3)
     numbers_str = leftpad + numbers_str
     #print "numbers_str:", numbers_str
     triplets = [numbers_str[x:x+3] for x in range(0,len(numbers_str),3)]
     #print "triplets are", triplets
     return triplets

def numbers_to_name(triplets):
     '''Create a name from each triplet and append the power of ten'''
     if triplets == ["000"]:
         return "zero"
     triplen = len(triplets) - 2
     number_name = ''

     #print "triplets are", triplets
     for triplet in triplets:
         #print "triplet is", triplet
         triplet_name = ''
         first, second, third, last_two = (triplet[0], triplet[1],
triplet[2], triplet[1:])
         if triplet == '000':
             triplen -= 1
             continue
         if first > '0':
             if last_two == '00': # special case - snip extra space 
separator
                 triplet_name += ones.get(first) + ' hundred'
             else:
                 triplet_name += ones.get(first) + ' hundred '
         if second == '0':
             if third > '0':
                 triplet_name += ones.get(third)
         elif second == '1':
             triplet_name += doubles.get(third)
         elif second > '1':
             triplet_name += tens.get(second)
             if third > '0':
                 triplet_name += '-' + ones.get(third)
         number_name += triplet_name
         if triplen > -1:
             number_name += powers_of_1000[triplen] + ', '
         triplen -= 1
     if number_name[-2] == ',':
         number_name = number_name[0:-2] # special case - snip 
extraneous ending comma
     return number_name

def int_name(i):
     triplets = make_triplets_from_input(str(i))
     return numbers_to_name(triplets)

# Main Program - turn numeric input into number-names
if __name__ == '__main__':
     if False:
         raw = get_raw_input()
         triplets = make_triplets_from_input(raw)
         print(numbers_to_name(triplets))



     from vegaseat import int2word

     def compare_em(i):
         a = int_name(i).replace("-", " ").replace(",", "")
         b = int2word(i).strip()
         if b == "": b = "zero"
         if a !=b:
             print(i, a, b)
             input("  press Enter to continue  ")

     for i in range(200001):
         compare_em(i)

     #The following shows a place where the vegaseat code
     # starts getting buggy.  In particular, it doesn't handle
     # numbers bigger than 999octillion or so.
     #Note, if we make a range starting at 10**30,
     # we get OverflowError, so we fake it
     start = 10**30 - 2
     for cntr in range(5):
         i = start + cntr
         compare_em(i)

     print "now starting random tests"
     for j in range(1000000):
         exponent = random.randint(4, 30)  #It appears that vegaseat is 
buggy beyond 999octillion
         i = random.randint(0, 10**exponent-1)
         compare_em(i)





-- 
DaveA



More information about the Tutor mailing list