[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