Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- # Filename: ipp5_0_phrase_anagrams.py
- # Version: 1.0.0
- # Author: Jeoi Reqi
- """
- Description:
- - This script demonstrates "Chapter 3: Project #5 - Phrase Anagrams" from the book "Impractical Python Projects" by Lee Vaughan.
- - This script allows users to interactively build an anagram phrase from the letters in their input phrase.
- - It loads a dictionary file, accepts a phrase from the user, and guides the user to construct an anagram phrase.
- - 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.
- Requirements:
- - Python 3.x
- - The following modules:
- - sys
- - requests
- Functions:
- - download_dictionary(url, file_name):
- - Description:
- - Downloads a dictionary file from a URL.
- - Parameters:
- - url (str): The URL from which to download the dictionary file.
- - file_name (str): The name to save the downloaded file as.
- - Raises:
- - requests.RequestException: If an error occurs during the HTTP request.
- - load_dictionary(file):
- - Description:
- - Opens a text file & turns its contents into a set of lowercase strings.
- - Parameters:
- - file (str): The name of the file to open.
- - Returns:
- - set: A set of lowercase strings containing the words from the file.
- - find_anagrams(name, word_set):
- - Description:
- - Find all valid anagram phrases from the given phrase using the provided word set.
- - Parameters:
- - name (str): The phrase to find anagram phrases for.
- - word_set (set): The set of words to use for finding anagram phrases.
- - Returns:
- - list: A list of valid anagram phrases.
- Usage:
- - Run the script.
- - Enter a name or phrase when prompted.
- - Select an anagram from the list of options.
- - Continue selecting anagrams until the phrase is complete.
- - Enter 0 to exit the program.
- Example Output:
- Downloading dictionary file from:
- https://raw.githubusercontent.com/dwyl/english-words/master/words_alpha.txt
- Dictionary file downloaded and saved alphabetically as: 'dictionary.txt'.
- Loading dictionary file...
- - Dictionary file contains 370105 words -
- This might take some time depending on the length of the name.
- Enter a name: trial and error
- - Length of Phrase = 13 -
- Press [ENTER] To Continue
- Due to the large number of anagrams, the list has been saved to 'anagram_list.txt'.
- Remaining letters = trialanderror
- Number of remaining letters = 13
- Number of remaining anagrams = 1689
- Current anagram name =
- Enter anagram index number or word (or... press [Enter] to reset or... 0 to exit): trial
- - Length of Phrase = 8 -
- Press [ENTER] To Continue
- 1. a
- 2. ad
- 3. ade
- 4. aden
- 5. ado
- 6. adon
- 7. ador
- 8. adore
- 9. adorer
- 10. adorn
- 11. adorner
- 12. adreno
- 13. ae
- 14. aeon
- 15. aer
- 16. aero
- 17. aeron
- 18. an
- 19. and
- ...
- 197. ronde
- 198. rone
- Remaining letters = anderror
- Number of remaining letters = 8
- Number of remaining anagrams = 198
- Current anagram name = trial
- Enter anagram index number or word (or... press [Enter] to reset or... 0 to exit): 19
- - Length of Phrase = 5 -
- Press [ENTER] To Continue
- 1. e
- 2. eo
- 3. er
- 4. err
- 5. error
- 6. o
- 7. oe
- 8. oer
- 9. or
- 10. ore
- 11. r
- 12. re
- 13. ro
- 14. roe
- 15. roer
- Remaining letters = error
- Number of remaining letters = 5
- Number of remaining anagrams = 15
- Current anagram name = trial and
- Enter anagram index number or word (or... press [Enter] to reset or... 0 to exit): 5
- *****FINISHED!!!*****
- Anagram of name = trial and error
- Try again? (Press 'ENTER' to continue or '0' to Exit): 0
- Exiting Program... GoodBye!
- Process ended with exit code 0.
- Additional Notes:
- - The script saves anagrams to a file named 'anagram_list.txt' if the number of anagrams is large.
- - Users can reset their current anagram phrase by pressing Enter.
- """
- import sys
- from collections import Counter
- import requests
- def download_dictionary(url, file_name):
- """
- Download a dictionary file from a URL and save it alphabetically.
- Parameters:
- url (str): The URL from which to download the dictionary file.
- file_name (str): The name to save the downloaded file as.
- Raises:
- requests.RequestException: If an error occurs during the HTTP request.
- """
- print("\nDownloading dictionary file from:\n" + "{}".format(url))
- try:
- response = requests.get(url)
- response.raise_for_status() # Check if the request was successful
- # Split the content by lines, strip whitespace, and sort alphabetically
- sorted_content = sorted(line.strip() for line in response.text.strip().split('\n'))
- # Save the sorted content to the file
- with open(file_name, 'w') as f:
- f.write('\n'.join(sorted_content))
- except requests.RequestException as e:
- print("\nError downloading dictionary from {}: {}".format(url, e))
- sys.exit(1)
- else:
- print("\nDictionary file downloaded and saved alphabetically as: '{}'.".format(file_name))
- def load_dictionary(file):
- """
- Open a text file & turn contents into a set of lowercase strings.
- Parameters:
- file (str): The name of the file to open.
- Returns:
- set: A set of lowercase strings containing the words from the file.
- """
- print("\nLoading dictionary file...")
- try:
- with open(file, encoding='utf-8') as in_file:
- loaded_txt = in_file.read().strip().split('\n')
- loaded_txt = {x.lower() for x in loaded_txt}
- return loaded_txt
- except IOError as e:
- print("{}\nError opening {}. Terminating program.".format(e, file))
- sys.exit(1)
- def save_anagrams_to_file(anagrams):
- """Save the list of anagrams to a file alphabetically."""
- sorted_anagrams = sorted(anagrams)
- with open('anagram_list.txt', 'w') as file:
- for idx, word in enumerate(sorted_anagrams, 1):
- file.write(f"{idx}. {word}\n")
- def find_anagrams(name, word_list):
- """Read name & dictionary file & display all anagrams in name."""
- name_letter_map = Counter(name)
- anagrams = []
- for word in word_list:
- word_letter_map = Counter(word.lower())
- if all(name_letter_map[letter] >= word_letter_map[letter] for letter in word_letter_map):
- anagrams.append(word)
- if len(anagrams) > 250:
- save_anagrams_to_file(anagrams)
- print("\nDue to the large number of anagrams, the list has been saved to 'anagram_list.txt'.")
- else:
- sorted_anagrams = sorted(anagrams)
- for idx, word in enumerate(sorted_anagrams, 1):
- print(f"{idx}. {word}")
- print("\nRemaining letters =", name)
- print("\nNumber of remaining letters =", len(name))
- print("\nNumber of remaining anagrams =", len(anagrams))
- return anagrams
- def process_choice(name, anagrams):
- """Check user choice for validity, return choice & leftover letters."""
- sorted_anagrams = sorted(anagrams)
- while True:
- try:
- choice = input('\nEnter anagram index number or word (or... press [Enter] to reset or... 0 to exit): ')
- if choice == '':
- return '', name # Start over
- elif choice == '0':
- sys.exit()
- else:
- try:
- choice_idx = int(choice) - 1
- if 0 <= choice_idx < len(sorted_anagrams):
- candidate = sorted_anagrams[choice_idx]
- left_over_list = list(name)
- for letter in candidate:
- if letter in left_over_list:
- left_over_list.remove(letter)
- else:
- print("\nInvalid input! Try again.\n", file=sys.stderr)
- break
- else:
- name = ''.join(left_over_list) # makes display more readable
- return candidate, name
- else:
- print("\nInvalid choice number. Try again.\n")
- except ValueError:
- if choice.lower() in sorted_anagrams:
- candidate = choice.lower()
- left_over_list = list(name)
- for letter in candidate:
- if letter in left_over_list:
- left_over_list.remove(letter)
- else:
- print("\nInvalid input! Try again.\n", file=sys.stderr)
- break
- else:
- name = ''.join(left_over_list) # makes display more readable
- return candidate, name
- else:
- print("\nInvalid input! Try again.\n", file=sys.stderr)
- except ValueError:
- print("\nInvalid input! Please enter a number.\n")
- def main():
- """Help user build anagram phrase from their name."""
- while True:
- ini_name = input("\nEnter a name: ")
- if not ini_name.strip():
- continue
- name = ''.join(ini_name.lower().split())
- name = name.replace('-', '')
- limit = len(name)
- phrase = ''
- running = True
- while running:
- temp_phrase = phrase.replace(' ', '')
- if len(temp_phrase) < limit:
- print(f"\n\t\t- Length of Phrase = {len(name)} -\n")
- input("Press [ENTER] To Continue")
- anagrams = find_anagrams(name, dict_file)
- print("\nCurrent anagram name =", end=" ")
- print(phrase, file=sys.stderr)
- choice, name = process_choice(name, anagrams)
- if choice == '':
- break # Start over
- phrase += choice + ' '
- elif len(temp_phrase) == limit:
- print("\n*****FINISHED!!!*****\n")
- print("Anagram of name =", end=" ")
- print(phrase, file=sys.stderr)
- print()
- try_again = input("Try again? (Press 'ENTER' to continue or '0' to Exit): ")
- if try_again.lower() == "0":
- print("\nExiting Program... GoodBye!")
- running = False
- sys.exit()
- else:
- break # Restart the process
- if __name__ == '__main__':
- # Define the URL and file name for the dictionary
- dictionary_url = "https://raw.githubusercontent.com/dwyl/english-words/master/words_alpha.txt"
- dictionary_file = "dictionary.txt"
- # Download and load the dictionary file
- download_dictionary(dictionary_url, dictionary_file)
- dict_file = load_dictionary(dictionary_file)
- # Ensure "a" & "i" (both lowercase) are included if not already in the dictionary
- if 'a' not in dict_file:
- dict_file.add('a')
- if 'i' not in dict_file:
- dict_file.add('i')
- print("\n\t\t- Dictionary file contains {} words -".format(len(dict_file)))
- print("\nThis might take some time depending on the length of the name.")
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement