CIT 590 Assignment 3: Number Namer
Fall 2015, David Matuszek

Purpose of this assignment

General idea of the assignment

In this assignment you will repeatedly read in a line from the keyboard, change any numbers found into words, and print out the resultant line. For example, if the input is
Today is Wednesday, September 9, 2015.
you would print out
Today is Wednesday, September nine, two thousand fifteen.

Details

Write and unit test the following methods, along with any others you may need:
def name_of_digit(n)
Takes an integer n in the range 0 to 9 and returns a lowercase string representation of that digit.
def name_of_tens(n)
Takes an integer n in the range 1 to 9 and returns a lowercase string representation of ten times that number. That is, it returns one of the strings 'ten', 'twenty', ..., 'ninety'.
def name_of_teens(n)
Takes an integer n in the range 10 to 19 and returns a lowercase string representation of that number. That is, it returns one of the strings 'ten', 'eleven', ..., 'nineteen'.
def name_of_integer(n)
Takes an integer n in the range 0 to 999999999 and returns a lowercase string representation of that number. That is, it returns one of the strings 'zero', 'one', ..., 'nine hundred ninety nine million nine hundred ninety nine thousand nine hundred ninety nine'. This method should use the preceding methods. The string should neither begin nor end with a blank. The string should not contain the word "and", which is used only when there is both an integer and a fractional part.
def name_of_fraction(tuple)
Takes a pair (2-tuple) of integers, where the tuple (n, d) represents the fraction n/d, and returns a string representation of that fraction. The first integer should be less than the second, and the second should be one of the numbers 10, 100, or 1000, representing tenths, hundredths, and thousandths, respectively. For example, name_of_fraction((0, 100)) should return 'zero hundredths', and name_of_fraction((70, 1000)) should return 'seventy thousandths'.
Special cases:
def name_of_decimal(n, tuple)
Takes an integer n, representing the integral part of a number, and a pair tuple, representing the fractional part of a number. It converts these two parts into strings, and conjoins them with the word and in between. For example, name_of_decimal(98, (7, 10)) should return 'ninety eight and seven tenths'.
Special cases: If either part is zero, omit that part, along with the word and. If both parts are zero, just return 'zero'.
def name_in_dollars(dollars, cents)
Takes two integers, dollars and cents, and produces a string representing that amount, including the word dollars and (possibly) the words and and cents. The value of cents should be less than 100. For example, name_in_dollars(12, 7) should return the string 'twelve dollars and seven cents'.
Special cases:
def name_of_number(str)
This is the "master" routine, called from main to do its magic, and it takes a string as its argument. The string must contain at least one digit, may have a dollar sign as its first character, and may contain a decimal point. This function will examine the string and decide which of the other functions to call to do its work.
def main()
Ask the user to type in sentences. For each line that is read in, the function prints out the corresponding sentence with numbers replaced by words. Spacing and punctuation should be preserved. Quits the program (by reaching the end of the main method) when the user enters a blank line. This is the only function that does input/output, and is the only function that does not require a unit test.

Hint: The first three of the above methods will be shorter and simpler if you use a dictionary, with integer keys and string values.

Hint: If n is a positive integer, then n % 10 is the rightmost digit of that integer, and n // 10 is all but the rightmost digit.

Follow the above rules, and don't look for other special cases. For example, if you don't do anything special, '7:30' will become 'seven:thirty', and that's okay.

Approach

  1. Create a file number_namer.py and fill it with "stub" functions. That is, all the functions (except main) should return the empty string.
  2. Create a file number_namer_test.py, and import the functions from number_namer.
  3. Write a test for one of the functions, and run it. It should fail.
  4. Write the function you just tested, and test it again. Debug until it passes the test.
  5. (Refactor) Clean up the code (improve spacing, remove redundancies, etc.) and make sure the test still passes.
  6. If you still have untested functions, go to step 3.

Expected results

The word zero is used for exactly one number--the number zero. It is not used for any other number. For example, the number 2008 is two thousand eight, despite all those zeros in it.

Note: The word zero may also occur in the result of directly calling name_of_fraction((0, d)), but that method should be called from name_of_decimal, which will treat a zero fraction as a special case.

Leading zeros don't change integers. Despite the James Bond movies, 007 is seven. (But .007 is, of course, seven thousandths.)

In this assignment, use the "teens" words only for the last two digits. While 1970 could be "nineteen seventy", the expected (and therefore correct) wording is one thousand nine hundred seventy.

Coda

At the end of your Python program (after all your function definitions), insert the following lines:

if __name__ == "__main__":
  main()

Due date

Zip your two Python files and submit them to Canvas by Wednesday, September 16.