Advertisement
Python253

ipp5_0_phrase_anagrams

May 31st, 2024 (edited)
620
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 12.14 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # Filename: ipp5_0_phrase_anagrams.py
  4. # Version: 1.0.0
  5. # Author: Jeoi Reqi
  6.  
  7. """
  8. Description:
  9.    - This script demonstrates "Chapter 3: Project #5 - Phrase Anagrams" from the book "Impractical Python Projects" by Lee Vaughan.
  10.    - This script allows users to interactively build an anagram phrase from the letters in their input phrase.
  11.    - It loads a dictionary file, accepts a phrase from the user, and guides the user to construct an anagram phrase.
  12.    - If the number of anagrams for a given phrase exceeds 250, the script saves the list of anagrams to a file named 'anagram_list.txt' in the current working directory.
  13.    
  14. Requirements:
  15.    - Python 3.x
  16.    - The following modules:
  17.        - sys
  18.        - requests
  19.  
  20. Functions:
  21.    - download_dictionary(url, file_name):
  22.        - Description:
  23.            - Downloads a dictionary file from a URL.
  24.        - Parameters:
  25.            - url (str): The URL from which to download the dictionary file.
  26.            - file_name (str): The name to save the downloaded file as.
  27.        - Raises:
  28.            - requests.RequestException: If an error occurs during the HTTP request.
  29.        
  30.    - load_dictionary(file):
  31.        - Description:
  32.            - Opens a text file & turns its contents into a set of lowercase strings.
  33.        - Parameters:
  34.            - file (str): The name of the file to open.
  35.        - Returns:
  36.            - set: A set of lowercase strings containing the words from the file.
  37.    
  38.    - find_anagrams(name, word_set):
  39.        - Description:
  40.            - Find all valid anagram phrases from the given phrase using the provided word set.
  41.        - Parameters:
  42.            - name (str): The phrase to find anagram phrases for.
  43.            - word_set (set): The set of words to use for finding anagram phrases.
  44.        - Returns:
  45.            - list: A list of valid anagram phrases.
  46.            
  47. Usage:
  48.    - Run the script.
  49.    - Enter a name or phrase when prompted.
  50.    - Select an anagram from the list of options.
  51.    - Continue selecting anagrams until the phrase is complete.
  52.    - Enter 0 to exit the program.
  53.  
  54. Example Output:
  55.  
  56.        Downloading dictionary file from:
  57.        https://raw.githubusercontent.com/dwyl/english-words/master/words_alpha.txt
  58.  
  59.        Dictionary file downloaded and saved alphabetically as: 'dictionary.txt'.
  60.  
  61.        Loading dictionary file...
  62.  
  63.                - Dictionary file contains 370105 words -
  64.  
  65.        This might take some time depending on the length of the name.
  66.  
  67.        Enter a name: trial and error
  68.  
  69.                - Length of Phrase = 13 -
  70.  
  71.        Press [ENTER] To Continue
  72.  
  73.        Due to the large number of anagrams, the list has been saved to 'anagram_list.txt'.
  74.  
  75.        Remaining letters = trialanderror
  76.  
  77.        Number of remaining letters = 13
  78.  
  79.        Number of remaining anagrams = 1689
  80.  
  81.        Current anagram name =
  82.  
  83.        Enter anagram index number or word (or... press [Enter] to reset or... 0 to exit): trial
  84.  
  85.                - Length of Phrase = 8 -
  86.  
  87.        Press [ENTER] To Continue
  88.        1. a
  89.        2. ad
  90.        3. ade
  91.        4. aden
  92.        5. ado
  93.        6. adon
  94.        7. ador
  95.        8. adore
  96.        9. adorer
  97.        10. adorn
  98.        11. adorner
  99.        12. adreno
  100.        13. ae
  101.        14. aeon
  102.        15. aer
  103.        16. aero
  104.        17. aeron
  105.        18. an
  106.        19. and
  107.        ...
  108.        197. ronde
  109.        198. rone
  110.  
  111.        Remaining letters = anderror
  112.  
  113.        Number of remaining letters = 8
  114.  
  115.        Number of remaining anagrams = 198
  116.  
  117.        Current anagram name = trial
  118.  
  119.        Enter anagram index number or word (or... press [Enter] to reset or... 0 to exit): 19
  120.  
  121.                - Length of Phrase = 5 -
  122.  
  123.        Press [ENTER] To Continue
  124.        1. e
  125.        2. eo
  126.        3. er
  127.        4. err
  128.        5. error
  129.        6. o
  130.        7. oe
  131.        8. oer
  132.        9. or
  133.        10. ore
  134.        11. r
  135.        12. re
  136.        13. ro
  137.        14. roe
  138.        15. roer
  139.  
  140.        Remaining letters = error
  141.  
  142.        Number of remaining letters = 5
  143.  
  144.        Number of remaining anagrams = 15
  145.  
  146.        Current anagram name = trial and
  147.  
  148.        Enter anagram index number or word (or... press [Enter] to reset or... 0 to exit): 5
  149.  
  150.        *****FINISHED!!!*****
  151.  
  152.        Anagram of name = trial and error
  153.  
  154.        Try again? (Press 'ENTER' to continue or '0' to Exit): 0
  155.  
  156.        Exiting Program...   GoodBye!
  157.  
  158.        Process ended with exit code 0.
  159.  
  160. Additional Notes:
  161.    - The script saves anagrams to a file named 'anagram_list.txt' if the number of anagrams is large.
  162.    - Users can reset their current anagram phrase by pressing Enter.
  163. """
  164.  
  165. import sys
  166. from collections import Counter  
  167. import requests
  168.  
  169. def download_dictionary(url, file_name):
  170.     """
  171.    Download a dictionary file from a URL and save it alphabetically.
  172.    
  173.    Parameters:
  174.        url (str): The URL from which to download the dictionary file.
  175.        file_name (str): The name to save the downloaded file as.
  176.    
  177.    Raises:
  178.        requests.RequestException: If an error occurs during the HTTP request.
  179.    """
  180.     print("\nDownloading dictionary file from:\n" + "{}".format(url))
  181.     try:
  182.         response = requests.get(url)
  183.         response.raise_for_status()  # Check if the request was successful
  184.        
  185.         # Split the content by lines, strip whitespace, and sort alphabetically
  186.         sorted_content = sorted(line.strip() for line in response.text.strip().split('\n'))
  187.        
  188.         # Save the sorted content to the file
  189.         with open(file_name, 'w') as f:
  190.             f.write('\n'.join(sorted_content))
  191.        
  192.     except requests.RequestException as e:
  193.         print("\nError downloading dictionary from {}: {}".format(url, e))
  194.         sys.exit(1)
  195.     else:
  196.         print("\nDictionary file downloaded and saved alphabetically as: '{}'.".format(file_name))
  197.  
  198. def load_dictionary(file):
  199.     """
  200.    Open a text file & turn contents into a set of lowercase strings.
  201.    
  202.    Parameters:
  203.        file (str): The name of the file to open.
  204.    
  205.    Returns:
  206.        set: A set of lowercase strings containing the words from the file.
  207.    """
  208.     print("\nLoading dictionary file...")
  209.     try:
  210.         with open(file, encoding='utf-8') as in_file:
  211.             loaded_txt = in_file.read().strip().split('\n')
  212.             loaded_txt = {x.lower() for x in loaded_txt}
  213.             return loaded_txt
  214.     except IOError as e:
  215.         print("{}\nError opening {}. Terminating program.".format(e, file))
  216.         sys.exit(1)
  217.  
  218. def save_anagrams_to_file(anagrams):
  219.     """Save the list of anagrams to a file alphabetically."""
  220.     sorted_anagrams = sorted(anagrams)
  221.     with open('anagram_list.txt', 'w') as file:
  222.         for idx, word in enumerate(sorted_anagrams, 1):
  223.             file.write(f"{idx}. {word}\n")
  224.  
  225. def find_anagrams(name, word_list):
  226.     """Read name & dictionary file & display all anagrams in name."""
  227.     name_letter_map = Counter(name)
  228.     anagrams = []
  229.     for word in word_list:
  230.         word_letter_map = Counter(word.lower())
  231.         if all(name_letter_map[letter] >= word_letter_map[letter] for letter in word_letter_map):
  232.             anagrams.append(word)
  233.     if len(anagrams) > 250:
  234.         save_anagrams_to_file(anagrams)
  235.         print("\nDue to the large number of anagrams, the list has been saved to 'anagram_list.txt'.")
  236.     else:
  237.         sorted_anagrams = sorted(anagrams)
  238.         for idx, word in enumerate(sorted_anagrams, 1):
  239.             print(f"{idx}. {word}")
  240.     print("\nRemaining letters =", name)
  241.     print("\nNumber of remaining letters =", len(name))
  242.     print("\nNumber of remaining anagrams =", len(anagrams))
  243.     return anagrams
  244.  
  245. def process_choice(name, anagrams):
  246.     """Check user choice for validity, return choice & leftover letters."""
  247.     sorted_anagrams = sorted(anagrams)
  248.     while True:
  249.         try:
  250.             choice = input('\nEnter anagram index number or word (or... press [Enter] to reset or... 0 to exit): ')
  251.             if choice == '':
  252.                 return '', name  # Start over
  253.             elif choice == '0':
  254.                 sys.exit()
  255.             else:
  256.                 try:
  257.                     choice_idx = int(choice) - 1
  258.                     if 0 <= choice_idx < len(sorted_anagrams):
  259.                         candidate = sorted_anagrams[choice_idx]
  260.                         left_over_list = list(name)
  261.                         for letter in candidate:
  262.                             if letter in left_over_list:
  263.                                 left_over_list.remove(letter)
  264.                             else:
  265.                                 print("\nInvalid input! Try again.\n", file=sys.stderr)
  266.                                 break
  267.                         else:
  268.                             name = ''.join(left_over_list)  # makes display more readable
  269.                             return candidate, name
  270.                     else:
  271.                         print("\nInvalid choice number. Try again.\n")
  272.                 except ValueError:
  273.                     if choice.lower() in sorted_anagrams:
  274.                         candidate = choice.lower()
  275.                         left_over_list = list(name)
  276.                         for letter in candidate:
  277.                             if letter in left_over_list:
  278.                                 left_over_list.remove(letter)
  279.                             else:
  280.                                 print("\nInvalid input! Try again.\n", file=sys.stderr)
  281.                                 break
  282.                         else:
  283.                             name = ''.join(left_over_list)  # makes display more readable
  284.                             return candidate, name
  285.                     else:
  286.                         print("\nInvalid input! Try again.\n", file=sys.stderr)
  287.         except ValueError:
  288.             print("\nInvalid input! Please enter a number.\n")
  289.  
  290. def main():
  291.     """Help user build anagram phrase from their name."""
  292.     while True:
  293.         ini_name = input("\nEnter a name: ")
  294.         if not ini_name.strip():
  295.             continue
  296.         name = ''.join(ini_name.lower().split())
  297.         name = name.replace('-', '')
  298.         limit = len(name)
  299.         phrase = ''
  300.         running = True
  301.         while running:
  302.             temp_phrase = phrase.replace(' ', '')
  303.             if len(temp_phrase) < limit:
  304.                 print(f"\n\t\t- Length of Phrase = {len(name)} -\n")
  305.                 input("Press [ENTER] To Continue")
  306.                 anagrams = find_anagrams(name, dict_file)
  307.                 print("\nCurrent anagram name =", end=" ")
  308.                 print(phrase, file=sys.stderr)
  309.                 choice, name = process_choice(name, anagrams)
  310.                 if choice == '':
  311.                     break  # Start over
  312.                 phrase += choice + ' '
  313.             elif len(temp_phrase) == limit:
  314.                 print("\n*****FINISHED!!!*****\n")
  315.                 print("Anagram of name =", end=" ")
  316.                 print(phrase, file=sys.stderr)
  317.                 print()
  318.                 try_again = input("Try again? (Press 'ENTER' to continue or '0' to Exit): ")
  319.                 if try_again.lower() == "0":
  320.                     print("\nExiting Program...   GoodBye!")
  321.                     running = False
  322.                     sys.exit()
  323.                 else:
  324.                     break  # Restart the process
  325.  
  326.  
  327. if __name__ == '__main__':
  328.     # Define the URL and file name for the dictionary
  329.     dictionary_url = "https://raw.githubusercontent.com/dwyl/english-words/master/words_alpha.txt"
  330.     dictionary_file = "dictionary.txt"
  331.  
  332.     # Download and load the dictionary file
  333.     download_dictionary(dictionary_url, dictionary_file)
  334.     dict_file = load_dictionary(dictionary_file)
  335.  
  336.     # Ensure "a" & "i" (both lowercase) are included if not already in the dictionary
  337.     if 'a' not in dict_file:
  338.         dict_file.add('a')
  339.     if 'i' not in dict_file:
  340.         dict_file.add('i')
  341.  
  342.     print("\n\t\t- Dictionary file contains {} words -".format(len(dict_file)))
  343.     print("\nThis might take some time depending on the length of the name.")
  344.  
  345.     main()
  346.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement