How Do You Write a Python Program to Simulate a Dial-by-Name directory?

Updated on 9/19/19 to use Python 3

Problem scenario
You have a list of first and last names in a file.  You want a program to extract the last names based on the first two or three letters.  You want to allow the user to dial by last name (to enter phone keys that correspond to letters of last names).  You want the user to enter a sequence of numbers that will correspond to the first two or three letters of the person's last name. 

How do you write a Python program that reads a text file on the same server and then prompts the user to dial by name with a touchtone keypad ("2" corresponds to "abc", "3" corresponds to "def", etc.) to return potential matches by last name?

Solution

1.  Create a file named list.txt that has names in this format (with no blank lines at the top or bottom):

Allen, Paul
Ballmer, Steve
Bell, Gordon
Berners-Lee, Tim
Bosack, Leonard
Brin, Sergey
Ellison, Larry
Gates, Bill
Jobs, Steve
Hopper, Grace
Lerner, Sandy
Li, Bruce
Moore, Gordon
Page, Larry
Torvalds, Linus
Turing, Alan
Watson, Thomas
Wozniack, Steve
Zuckerberg, Mark

2.  Use this as the program:

# This is for Python 3. It was written by continualintegration.com
# It requires that a file named list.txt be in the same directory.  
""" Written by continualintegration.com.  Usage instructions:
    This program needs to be in the same directory as a file called list.txt.
    You would run the program like this: "python phone.py"
    The content of list.txt can be as follows:

Allen, Paul
Ballmer, Steve
Bell, Gordon
Berners-Lee, Tim
Bosack, Leonard
Brin, Sergey
Ellison, Larry
Gates, Bill
Jobs, Steve
Hopper, Grace
Lerner, Sandy
Li, Bruce
Moore, Gordon
Page, Larry
Torvalds, Linus
Turing, Alan
Watson, Thomas
Wozniack, Steve
Zuckerberg, Mark
"""

def phone():
  pad = """This is the keypad.  Press a number key that corresponds to the letter of the name.
  Enter a minimum of two and a maximum of three numbers.

  1
  2 ABC
  3 DEF
  4 GHI
  5 JKL
  6 MNO
  7 PQRS
  8 TUV
  9 WXYZ
  0"""

  print(" ")
  print(pad)
  first = input("Please enter the first three letters of the person's last name: ")

  if len(first) < 2:
    print("you entered too few numbers")
    print("Please try again")
    return 'DO_OVER_FLAG'

  if len(first) > 3:
    print("you entered too many numbers")
    print("Please try again")
    return 'DO_OVER_FLAG'

  if first[0] == '0':
    print("0 is not a valid key.")
    print("Please try again.")
    return 'DO_OVER_FLAG'

  if first[0] == '1':
    print("1 is not a valid key.")
    print("Please try again.")
    return 'DO_OVER_FLAG'

  if first[0].isalpha():
    print("enter numbers only")
    print("Please try again.")
    return 'DO_OVER_FLAG'

  if first[1].isalpha():
    print("enter numbers only")
    print("Please try again.")
    return 'DO_OVER_FLAG'

  if len(first) == 3:
    if first[2].isalpha():
      print("enter numbers only")
      print("Please try again.")
      return 'DO_OVER_FLAG'

  print("This was valid input")
  return first


def telparser(astring):
  if astring[0] == '2':
    firstletter = 'ABC'
  if astring[0] == '3':
    firstletter = 'DEF'
  if astring[0] == '4':
    firstletter = 'GHI'
  if astring[0] == '5':
    firstletter = 'JKL'
  if astring[0] == '6':
    firstletter = 'MNO'
  if astring[0] == '7':
    firstletter = 'PQRS'
  if astring[0] == '8':
    firstletter = 'TUV'
  if astring[0] == '9':
    firstletter = 'WXYZ'

  if astring[1] == '2':
    secondletter = 'ABC'
  if astring[1] == '3':
    secondletter = 'DEF'
  if astring[1] == '4':
    secondletter = 'GHI'
  if astring[1] == '5':
    secondletter = 'JKL'
  if astring[1] == '6':
    secondletter = 'MNO'
  if astring[1] == '7':
    secondletter = 'PQRS'
  if astring[1] == '8':
    secondletter = 'TUV'
  if astring[1] == '9':
    secondletter = 'WXYZ'

  if len(astring) > 2:
    if astring[2] == '2':
      thirdletter = 'ABC'
    if astring[2] == '3':
      thirdletter = 'DEF'
    if astring[2] == '4':
      thirdletter = 'GHI'
    if astring[2] == '5':
      thirdletter = 'JKL'
    if astring[2] == '6':
      thirdletter = 'MNO'
    if astring[2] == '7':
      thirdletter = 'PQRS'
    if astring[2] == '8':
      thirdletter = 'TUV'
    if astring[2] == '9':
      thirdletter = 'WXYZ'
    return firstletter, secondletter, thirdletter
  else:
    return firstletter, secondletter


def finder(content):
  goodlist = []
  finallist = []
  prebook=open('list.txt', 'r')
  book = prebook.read()
  postbook = book.split('\n')
  postbook = postbook[:-1]
  d00 = str(content[0][0])
  d01 = str(content[0][1])
  d02 = str(content[0][2])
  if len(content[0]) > 3:
    d03 = str(content[0][3])

  for item in postbook:
    item0 = str(item[0])
    if d00.upper() == item0.upper():    # Test first letter of last name against the first character of first three letters o
      goodlist.append(item)
    elif d01.upper() == item0.upper():
      goodlist.append(item)
    elif d02.upper() == item0.upper():
      goodlist.append(item)
    else:
      if len(content[0]) > 3:
        if d03.upper() == item0.upper():
          goodlist.append(item)

  for item in goodlist:
    item1 = str(item[1])
    d10 = str(content[1][0])
    d11 = str(content[1][1])
    d12 = str(content[1][2])
    if len(content[1]) > 3:
      d13 = str(content[1][3])


    if d10.upper() == item1.upper():    # Test second letter of last name against the second character of first three letters
      finallist.append(item)
    elif d11.upper() == item1.upper():
      finallist.append(item)
    elif d12.upper() == item1.upper():
      finallist.append(item)
    else:
      if len(content[1]) > 3:
        if d13.upper() == item1.upper():
          finallist.append(item)
  if len(finallist) == 0:
    finallist.append("No names matched that entry.")


  return finallist


try:      # It is easy to forget that the program needs an extra file.
  toprint = phone()
except FileNotFoundError:
  print("")
  print("*********************************")
  print("FATAL ERROR")
  print("You need to create a list.txt file that is in the same directory as this program.")
  print("See this web page: http://www.continualintegration.com/miscellaneous-articles/how-do-you-write-a-python-program-to-s
  print("Step #1 of the solution in the web page above will help you.")
  print("The program will now exit.")
  quit()

while toprint == 'DO_OVER_FLAG':
  toprint = phone()


intermed = telparser(toprint)

r = finder(intermed)
print("We searched for matches and we found ...")
for x in r:
  print(x)

      

Here is a Python 2 version (but we know it does not work as well):

# Written by continualintegration.com
""" Written by continualintegration.com.  Usage instructions:
    This program needs to be in the same directory as a file called list.txt.
    The content of list.txt can be as follows:

Allen, Paul
Ballmer, Steve
Bell, Gordon
Berners-Lee, Tim
Bosack, Leonard
Brin, Sergey
Ellison, Larry
Gates, Bill
Jobs, Steve
Hopper, Grace
Lerner, Sandy
Li, Bruce
Moore, Gordon
Page, Larry
Torvalds, Linus
Turing, Alan
Watson, Thomas
Wozniack, Steve
Zuckerberg, Mark

# The term "MARK" in the program is just a designated value for logic.
# Do not confuse it with Mr. Zuckerberg's first name.
# Use "python phone.py" to run this program.

"""
import re

def phone():
  pad = """This is the keypad.  Press a number key that corresponds to the letter of the name.
  Enter a minimum of two and a maximum of three numbers.

  1
  2 ABC
  3 DEF
  4 GHI
  5 JKL
  6 MNO
  7 PQRS
  8 TUV
  9 WXYZ
  0"""

  print pad
  first = raw_input("Please enter the first three letters of the person's last name: ")

  prebook=open('list.txt', 'r')
  book = prebook.read()
  postbook = book.split('\n')
  global i;
  i = -1

  def presearch(digit, i):   #Digit is the key they entered.
    intermediate = []
    finvar = "initial"
    if (digit == '0'):
      finvar = "***Invalid key error!!!  0 has no letters associated with it. ABORTIVE ERROR"  
    elif digit == '1':
      finvar = "***invalid key error!!!  1 has no letters associated with it. ABORTIVE ERROR."  
    elif digit == '2':
      prevar1 = search('A', i)
      prevar2 = search('B', i)
      prevar3 = search('C', i)
      if (prevar1 == []):
        if (prevar2 == []):
          if (prevar3 == []):
            if (i == 0): place = 'first'
            if (i == 1): place = 'second'
            if (i == 3): place = 'third'
        finvar = '***No name found that starts with an "A", "B", or "C" in the ' + place + ' letter.'
      if (prevar1 != []): intermediate.extend(prevar1)
      if (prevar2 != []): intermediate.extend(prevar2) # Append would preserve groupings by first letter
      if (prevar3 != []): intermediate.extend(prevar3)
      finvar = intermediate

    elif digit == '3':
      prevar1 = search('D', i)
      prevar2 = search('E', i)
      prevar3 = search('F', i)
      if (prevar1 == []):
        if (prevar2 == []):
          if (prevar3 == []):
            if (i == 0): place = 'first'
            if (i == 1): place = 'second'
            if (i == 3): place = 'third'
            finvar = '***No name found that starts with an "D", "E", or "F" in the ' + place + ' letter.'
      if (prevar1 != []): intermediate.extend(prevar1)
      if (prevar2 != []): intermediate.extend(prevar2) # Append would preserve groupings by first letter
      if (prevar3 != []): intermediate.extend(prevar3)
      finvar = intermediate

    elif digit == '4':
      prevar1 = search('G', i)
      prevar2 = search('H', i)
      prevar3 = search('I', i)
      if (prevar1 == []):
        if (prevar2 == []):
          if (prevar3 == []):
            if (i == 0): place = 'first'
            if (i == 1): place = 'second'
            if (i == 3): place = 'third'
            finvar = '***No name found that starts with an "G", "H", or "I" in the ' + place + ' letter.'
      if (prevar1 != []): intermediate.extend(prevar1)
      if (prevar2 != []): intermediate.extend(prevar2) # Append would preserve groupings by first letter
      if (prevar3 != []): intermediate.extend(prevar3)
      finvar = intermediate

    elif digit == '5':
      prevar1 = search('J', i)
      prevar2 = search('K', i)
      prevar3 = search('L', i)
      if (prevar1 == []):
        if (prevar2 == []):
          if (prevar3 == []):
              if (i == 0): place = 'first'
              if (i == 1): place = 'second'
              if (i == 3): place = 'third'
              finvar = '***No name found that starts with an "J", "K", or "L" in the ' + place + ' letter.'
      if (prevar1 != []): intermediate.extend(prevar1)
      if (prevar2 != []): intermediate.extend(prevar2) # Append would preserve groupings by first letter
      if (prevar3 != []): intermediate.extend(prevar3)
      finvar = intermediate

    elif digit == '6':
      prevar1 = search('M', i)
      prevar2 = search('N', i)
      prevar3 = search('O', i)
      if (prevar1 == []):
        if (prevar2 == []):
          if (prevar3 == []):
              if (i == 0): place = 'first'
              if (i == 1): place = 'second'
              if (i == 3): place = 'third'
              finvar = '***No name found that starts with an "M", "N", or "O" in the ' + place + ' letter.'
      if (prevar1 != []): intermediate.extend(prevar1)
      if (prevar2 != []): intermediate.extend(prevar2) # Append would preserve groupings by first letter
      if (prevar3 != []): intermediate.extend(prevar3)
      finvar = intermediate

    elif digit == '7':
      prevar1 = search('P', i)
      prevar2 = search('Q', i)
      prevar3 = search('R', i)
      prevar4 = search('S', i)
      if (prevar1 == []):
        if (prevar2 == []):
          if (prevar3 == []):
            if (prevar4 == []):
                if (i == 0): place = 'first'
                if (i == 1): place = 'second'
                if (i == 3): place = 'third'
                finvar = '***No name found that starts with an "P", "Q", "R", or "S" in the ' + place + ' letter.'
      if (prevar1 != []): intermediate.extend(prevar1)
      if (prevar2 != []): intermediate.extend(prevar2) # Append would preserve groupings by first letter
      if (prevar3 != []): intermediate.extend(prevar3)
      if (prevar4 != []): intermediate.extend(prevar4)
      finvar = intermediate

    elif digit == '8':
      prevar1 = search('T', i)
      prevar2 = search('U', i)
      prevar3 = search('V', i)
      if (prevar1 == []):
        if (prevar2 == []):
          if (prevar3 == []):
            if (i == 0): place = 'first'
            if (i == 1): place = 'second'
            if (i == 3): place = 'third'
            finvar = '***No name found that starts with an "T", "U", or "V" in the ' + place + ' letter.'
      if (prevar1 != []): intermediate.extend(prevar1)
      if (prevar2 != []): intermediate.extend(prevar2) # Append would preserve groupings by first letter
      if (prevar3 != []): intermediate.extend(prevar3)
      finvar = intermediate

    elif digit == '9':
      prevar1 = search('W', i)
      prevar2 = search('X', i)
      prevar3 = search('Y', i)
      prevar4 = search('Z', i)
      if (prevar1 == []):
        if (prevar2 == []):
          if (prevar3 == []):
            if (i == 0): place = 'first'
            if (i == 1): place = 'second'
            if (i == 3): place = 'third'
            finvar = '***No name found that starts with an "W", "X", "Y", or "Z" in the ' + place + ' letter.'
      if (prevar1 != []): intermediate.extend(prevar1)
      if (prevar2 != []): intermediate.extend(prevar2) # Append would preserve groupings by first letter
      if (prevar3 != []): intermediate.extend(prevar3)
      if (prevar4 != []): intermediate.extend(prevar4)
      finvar = intermediate

    else: print "You cannot enter letters.  You must enter numbers only."
    if finvar == []: finvar = "***No names were found."
    return finvar

  def search(letter, pos):  # Take two parameters a string of 0 to 2 characters and the letter it is searching for
    potential = []
    for line in book.splitlines():
      if (line[pos] == letter):
        potential.append(line)
    return potential

  def secondkeyreducer(shortlist, seckey): #should rename to getnames
    potentiala = []
    ee = len(shortlist)
    x = 0
    while (x < ee):
      name = shortlist[x] # name in shortlist:
      if name == '*': x = x + ee # get out of while loop if no names were found
      tt = eliminator(name, seckey, 1)
      if (tt == 'MARK'): potentiala.append(name)
      elif (tt == 'FAILED'): quit()
      else: print "" #"not adding a name because of 2nd or 3rd key"
      x = x + 1
    return potentiala

  def thirdkeyreducer(shortlist, thirdkey): #should rename to getnames
    potentiala = []
    ee = len(shortlist)
    x = 0
    while (x < ee):
      name = shortlist[x] # name in shortlist:
      tt = eliminator(name, thirdkey, 2)
      if (tt == 'MARK'): potentiala.append(name)
      elif (tt == 'FAILED'): quit()
      else: print "" #"not adding a name because of 2nd or 3rd key"
      x = x + 1
    if potentiala == []:
      print "No names were found by the spelling of that name."
      phone()    
    else: print "" # potentiala #print all potential matches
    return potentiala

  def eliminator(name, seckey, itera):
    val = 'REMOVE'
    if name != '*':
      if seckey == '0': val = 'FAILED'
      if seckey == '1': val = 'FAILED'
      if seckey == '2':
        if name[itera].upper() in ['A', 'B', 'C']: val = 'MARK'
      if seckey == '3':
        if name[itera].upper() in ['D', 'E', 'F']: val = 'MARK'
      if seckey == '4':
        if name[itera].upper() in ['G', 'H', 'I']: val = 'MARK'
      if seckey == '5':
        if name[itera].upper() in ['J', 'K', 'L']: val = 'MARK'
      if seckey == '6':
        if name[itera].upper() in ['M', 'N', 'O']: val = 'MARK'
      if seckey == '7':
        if name[itera].upper() in ['P', 'Q', 'R', 'S']: val = 'MARK'
      if seckey == '8':
        if name[itera].upper() in ['T', 'U', 'V']: val = 'MARK'
      if seckey == '9':
        if name[itera].upper() in ['W', 'X', 'Y', 'Z']: val = 'MARK'
    return val

  inivar = first[0]
  firstlist = presearch(inivar, 0)
  cc = len(firstlist)

  if len(first) < 2:
    print "you entered too few numbers"
    print "try again"
    phone()

  if len(first) > 3:
    print "you entered too many numbers"
    print "try again"
    phone()

  if first[0].isalpha():
    print "enter numbers only"
    print "Call back again."
    phone()

  if first[1].isalpha():
    print "enter numbers only"
    print "Call back again."
    phone()

  if len(first) == 3:
    if first[2].isalpha():
      print "enter numbers only"
      print "Call back again."
      phone()

  yt = first[1]
  secondlist = secondkeyreducer(firstlist, yt)

  if len(first) == 3:
     zt = first[2]
     thirdlist = thirdkeyreducer(secondlist, zt)
     return thirdlist
  else:
    return secondlist

toprint = phone()
print toprint 

Leave a comment

Your email address will not be published. Required fields are marked *