Hello this exercise says:
Create a Mad Libs program that reads in text files and lets the user add their own text anywhere the word ADJECTIVE, NOUN, ADVERB, or VERB appears in the text file.
textfile = The ADJECTIVE panda walked to the NOUN and then VERB. A nearby NOUN was
unnafected by these events.
What I have so far is :
import re
#filename = input('Input the Filename: ')
with open('madlibs.txt') as file:
content = file.read()
file.close()
regex = re.compile(r'ADJECTIVE|NOUN|VERB|ADVERB')
#regex = re.compile('[A-Z]{3,}')
matches = regex.findall(content)
#newWord = []
for word in matches:
user_input = input('Enter %s: ' % word)
# newWord.append(user_input)
new_content = content.replace(word,user_input,1)
print(new_content)
My input is:
Enter ADJECTIVE: heavy
Enter NOUN: whale
Enter VERB: runs
Enter NOUN: door
And my output:
The ADJECTIVE panda walked to the door and then VERB. A nearby door was
unnafected by these events.
Can someone explain to me what I'm doing wrong? It seems that I can't change ADJECTIVE and VERB for some reason, i also tried the commented regex with uppercase and it does the same so the problem is somewhere else.
You need to change content, but because you aren't, it's overwriting your changes until the very last word:
for word in matches:
user_input = input('Enter %s: ' % word)
content = content.replace(word,user_input) # overwrite content here
print(content)
Or, if you prefer to keep content the same:
new_content = content
for word in matches:
user_input = input('Enter %s: ' % word)
new_content = new_content.replace(word,user_input) # overwrite new_content here
print(new_content)
Strings in python are immutable, meaning that they will not be changed in-place, and instead must be re-assigned:
somestring = "this is a string"
for word in ["is", "a"]:
newstring = somestring.replace(word, "aaaa")
print(newstring)
# this is aaaa string
print(somestring)
# this is a string
Note that somestring is still the original value. The first replace did happen, it just was overwritten when the result of somestring.replace("a", "aaaa") was reassigned.
Broken into steps:
somestring = "this is a string"
newstring = somestring.replace("is", "aaaa")
# this aaaa a string
newstring = somestring.replace("a", "aaaa")
# this is aaaa string
#! /usr/bin/python3
# mad_libs.py - Playing mad libs game
# Usage: python3 mad_libs.py save - Save a mad lib phrase from clip board
# python3 mad_libs.py - Play the mad libs game.
# Caution: Must save at least one phrase before playing.
import shelve, pyclip, random, sys, re
import pyinputplus as pyi
# Open shelve file
shelfFile = shelve.open('mad_libs')
# Add phrase to the database by pasting from clipboard
if len(sys.argv) == 2 and sys.argv[1] == 'save':
shelfFile[str(len(shelfFile))] = pyclip.paste().decode()
print("Phrase saved.")
sys.exit()
# Get a random phrase from database and display
phrase = shelfFile[str(random.randrange(len(shelfFile)))]
# Regex for finding match
matLibsRegex = re.compile(r'(ADJECTIVE)|(NOUN)|(VERB)|(ADVERB)')
print(phrase)
while True:
# Find all the matches and replace with user's input
match = matLibsRegex.search(phrase)
if match == None: # Return None if there is no match
break
prompt = f"Enter an {match.group().lower()}: " if match.group(
)[0] in 'Aa' else f"Enter a {match.group().lower()}: "
substitute = pyi.inputStr(prompt)
phrase = phrase.replace(match.group(), substitute, 1) # Replace the fill-in space with user's input
# Print the final phrase and save it to file
print(phrase)
result = open('mad_libs_result.txt', 'a')
result.write(phrase + '\n')
result.close()
shelfFile.close()
I hope this could enhance your code.
Since this post is about mad libs and I would like to drop my solutions here for upcoming learners. I combine the functionality of Mad Libs exercise and Extend Multi-Clipbaord exercise.
Related
photo
This code can't load the log.txt file.
The file is in the temp folder.
Why can't I load it?
This code only displays the text: Search word: ABC.
text = input("Search word: ABC")
with open("C:\Temp\log.txt", encoding = "utf-8") as f:
cnt = 0
for line in f:
l = line.strip().split()
if (l[-1] == text):
print(line.strip())
cnt += 1
if (cnt): print(cnt, "count")
else: print(text, "No data.")
It seems like you need to type the word after running the program. The "ABC" you see is the prompt from the script i.e. it is not entered by you. That's why the program keeps running, waiting for the input and doesn't go further.
Here's your code slightly modified to make it clear.
text = input("Search word: ")
with open("C:\Temp\log.txt", encoding="utf-8") as f:
cnt = 0
for line in f:
if text in line:
print(line.strip())
cnt += 1
if cnt:
print(cnt, "count")
else:
print(text, "No data.")
I guess you understand that your code:
ask the user to input some text
count the occurrences of that text in the file C:\Temp\log.txt, under the conditions:
the text does not contains space
the text is at the end of the line
the text may be followed by one or more spaces
the text must be preceded by one or more spaces
the file cannot have empty lines
Under those conditions, your code should behave nicely. I would recommend to change text = input("Search word: ABC") to text = input("Search word: ") to make it clear that the user need to input some text.
If you still have unexpected results, check if you don't have any character encoding issue (like a terminal default encoding not being utf-8)
create a list of word strings by reading this file. Then loop over each word in this list, passing it to the decrypt() method. If this method returns the integer 0, the password was wrong and your program should continue to the next password. If decrypt() returns 1, then your program should break out of the loop and print the hacked password. You should try both the uppercase and lower-case form of each word.
This dictionary.txt file contains words in capital letters.
> import PyPDF2
pdfFile = open('reverse.pdf', 'rb')
pdfReader = PyPDF2.PdfFileReader(pdfFile)
pdfWriter = PyPDF2.PdfFileWriter()
for pageNum in range(pdfReader.numPages):
pdfWriter.addPage(pdfReader.getPage(pageNum))
wrd = input('Please enter one word as a password: ')
pdfWriter.encrypt(wrd)
resultPdf = open('encryptedreverse.pdf', 'wb')
pdfWriter.write(resultPdf)
resultPdf.close()
print(pdfReader.isEncrypted)
helloDict = open('dictionary.txt')
helloDictCont = helloDict.read().splitlines()
liDict = []
for word in helloDictCont:
liDict.extend(word.split())
PdfFile2 = open('encryptedreverse.pdf', 'rb')
pdfReader2 = PyPDF2.PdfFileReader(PdfFile2)
print(pdfReader2.isEncrypted)
for word in liDict:
if pdfReader2.decrypt(word) == 1:
break
print(word)
elif pdfReader2.decrypt(word.lower()) == 1:
break
print(word)
After a few minutes processing ends and I neither get a password printed nor the pdf file is decrypted. Any idea what am I doing wrong?
This works fine for me:
import PyPDF2
pdfFile = open('reverse.pdf', 'rb')
pdfReader = PyPDF2.PdfFileReader(pdfFile)
pdfWriter = PyPDF2.PdfFileWriter()
for pageNum in range(pdfReader.numPages):
pdfWriter.addPage(pdfReader.getPage(pageNum))
wrd = input('Please enter one word as a password: ')
pdfWriter.encrypt(wrd)
resultPdf = open('encryptedreverse.pdf', 'wb')
pdfWriter.write(resultPdf)
resultPdf.close()
print(pdfReader.isEncrypted)
helloDict = open('t.txt')
helloDictCont = helloDict.read().splitlines()
liDict = []
for word in helloDictCont:
liDict.extend(word.split())
PdfFile2 = open('encryptedreverse.pdf', 'rb')
pdfReader2 = PyPDF2.PdfFileReader(PdfFile2)
print(pdfReader2.isEncrypted)
for word in liDict:
if pdfReader2.decrypt(word) == 1:
print('The correct PWD as upper case: ' + word)
break
elif pdfReader2.decrypt(word.lower()) == 1:
print('The correct PWD as lower case: ' + word)
break
else:
print('PWD is not correct: ' + word)
Here's my solution:
'''
Brute-Force PDF Password Breaker
Say you have an encrypted PDF that you have forgotten the password to,
but you remember it was a single English word. Trying to guess your forgot-
ten password is quite a boring task. Instead you can write a program that
will decrypt the PDF by trying every possible English word until it finds one
that works. This is called a brute-force password attack. Download the text file
dictionary.txt from https://nostarch.com/automatestuff2/. This dictionary file
contains over 44,000 English words with one word per line.
Using the file-reading skills you learned in Chapter 9, create a list of
word strings by reading this file. Then loop over each word in this list, pass -
ing it to the decrypt() method. If this method returns the integer 0, the pass-
word was wrong and your program should continue to the next password.
If decrypt() returns 1, then your program should break out of the loop and
print the hacked password. You should try both the uppercase and lower-
case form of each word. (On my laptop, going through all 88,000 uppercase
and lowercase words from the dictionary file takes a couple of minutes. This
is why you shouldn’t use a simple English word for your passwords.)
'''
import PyPDF2
import time
import os
import sys
def decrypt():
ok = False
print(f'Working... {time.asctime()}')
start = time.time()
passwords = open(dictionary).read().split('\n')
pdfReader = PyPDF2.PdfFileReader(pdf)
if pdfReader.isEncrypted:
for password in passwords:
if pdfReader.decrypt(password) or pdfReader.decrypt(password.lower()):
print(f'Password: {password}')
ok = True
break
end = time.time()
hours = int((end - start) / 3600)
minutes = int((end - start) / 60)
secondes = int(end - start - (hours * 3600) - (minutes * 60))
if ok:
print(f'Has been decrypted in {hours}H:{minutes}M:{secondes}S!')
else:
print(f'{pdf} hasn\'t been decrypted... Maybe need a better dictionary?')
else:
print(f'{pdf} isn\'t encrypted')
if len(sys.argv) == 3:
dictionary, pdf = sys.argv[1], sys.argv[2]
if os.path.isfile(dictionary) and dictionary.endswith('.txt'):
if os.path.isfile(pdf) and pdf.endswith('.pdf'):
decrypt()
else:
print('Invalid path to pdf or pdf file')
else:
print('Invalid path to dictionary or dictionary file')
else:
print('Please enter arguments as example:\
\ndictionaryName.txt pdfName.pdf')
I am trying to use the replace function to take items from a list and replace the fields below with their corresponding values, but no matter what I do, it only seems to work when it reaches the end of the range (on it's last possible value of i, it successfully replaces a substring, but before that it does not)
for i in range(len(fieldNameList)):
foo = fieldNameList[i]
bar = fieldValueList[i]
msg = msg.replace(foo, bar)
print msg
This is what I get after running that code
<<name>> <<color>> <<age>>
<<name>> <<color>> <<age>>
<<name>> <<color>> 18
I've been stuck on this for way too long. Any advice would be greatly appreciated. Thanks :)
Full code:
def writeDocument():
msgFile = raw_input("Name of file you would like to create or write to?: ")
msgFile = open(msgFile, 'w+')
msg = raw_input("\nType your message here. Indicate replaceable fields by surrounding them with \'<<>>\' Do not use spaces inside your fieldnames.\n\nYou can also create your fieldname list here. Write your first fieldname surrounded by <<>> followed by the value you'd like to assign, then repeat, separating everything by one space. Example: \"<<name>> ryan <<color>> blue\"\n\n")
msg = msg.replace(' ', '\n')
msgFile.write(msg)
msgFile.close()
print "\nDocument written successfully.\n"
def fillDocument():
msgFile = raw_input("Name of file containing the message you'd like to fill?: ")
fieldFile = raw_input("Name of file containing the fieldname list?: ")
msgFile = open(msgFile, 'r+')
fieldFile = open(fieldFile, 'r')
fieldNameList = []
fieldValueList = []
fieldLine = fieldFile.readline()
while fieldLine != '':
fieldNameList.append(fieldLine)
fieldLine = fieldFile.readline()
fieldValueList.append(fieldLine)
fieldLine = fieldFile.readline()
print fieldNameList[0]
print fieldValueList[0]
print fieldNameList[1]
print fieldValueList[1]
msg = msgFile.readline()
for i in range(len(fieldNameList)):
foo = fieldNameList[i]
bar = fieldValueList[i]
msg = msg.replace(foo, bar)
print msg
msgFile.close()
fieldFile.close()
###Program Starts#####--------------------
while True==True:
objective = input("What would you like to do?\n1. Create a new document\n2. Fill in a document with fieldnames\n")
if objective == 1:
writeDocument()
elif objective == 2:
fillDocument()
else:
print "That's not a valid choice."
Message file:
<<name>> <<color>> <<age>>
Fieldname file:
<<name>>
ryan
<<color>>
blue
<<age>>
18
Cause:
This is because all lines except the last line read from the "Fieldname" file contains "\n" characters. So when the program comes to the replacing part fieldNameList , fieldValueList and msg looks like this:
fieldNameList = ['<<name>>\n', '<<color>>\n', '<<age>>\n']
fieldValueList = ['ryan\n', 'blue\n', '18']
msg = '<<name>> <<color>> <<age>>\n'
so the replace() function actually searches for '<<name>>\n','<<color>>\n','<<age>>\n' in msg string and only <<age>> field get replaced.(You must have a "\n" at the end of msg file, otherwise it won't be replaced as well).
Solution:
use rstrip() method when reading lines to strip the newline character at the end.
fieldLine = fieldFile.readline().rstrip()
I am searching a text file for an input word. However, I am only meant to search the text in the file after the word "START". The first twenty-odd before "START" should be ignored. I know how to find "START", but not how to search the rest of the file once "START" is encountered. I would appreciate any guidance!
Here is what I have so far:
file = open("EnglishWords.txt", "r")
print("***** Anagram Finder *****")
word = input("Enter a word: ")
for line in file:
if "START" in line:
if word in line:
print("Yes, ", word, " is in the file.", sep="")
else:
print("Sorry, ", word, " is not in the file.", sep="")
file.close()
Here is a sample of the text file:
The name of Princeton University or Princeton may not be
used in advertising or publicity pertaining to
distribution of the software and/or database. Title to
copyright in this software, database and any associated
documentation shall at all times remain with Princeton
University and LICENSEE agrees to preserve same.
START
clobber
transversalis
squinter
cunner
damson
extrovertive
absorptive
Modifying your code, we have
file = open("EnglishWords.txt", "r")
print("***** Anagram Finder *****")
word = input("Enter a word: ")
start_looking = False
word_found = False
for line in file:
if not start_looking:
if "START" in line:
start_looking = True
else:
continue
if word in line:
print("Yes, ", word, " is in the file.", sep="")
word_found = True
break
if not word_found:
print("Sorry, ", word, " is not in the file.", sep="")
file.close()
As long as START hasn't been found, keep skipping over the lines of the file. If, however, you encounter START, reset your flag and begin looking.
Do a for after your word is found:
with open(myfile, 'r') as f:
for line in f:
if 'START' in line:
# do stuff to lines below 'START'
# you could do another for loop here to iterate
for line in f:
print (line) # just an example
Very similar to this other SO post. Credit for the syntax of my answer comes from its answer.
What about something with regex module ?
re.findall(r"START.*(word_to_search).*", entire_text)
This should return you the result only if there is a START before the word to search for. I hope that's what you're looking for.
EDIT :
For a solution line by line i would go with something like :
start_search = 0
with open(bigfile, "r") as f:
for line in f:
if "START" IN line:
start_search = 1
if start_search and word_to_search in line:
print("result foun")
return (word_to_search)
What about this ?
Keep it short, simple and explicit:
with open("EnglishWords.txt", 'r') as fin:
output = fin.readlines()
# Find the line that contains START
index = output.index("START")
# Search all the lines after that
for line in output[index+1:]:
if word in line:
print("Yes, ", word, " is in the file.", sep="")
else:
print("Sorry, ", word, " is not in the file.", sep="")
You could use Python's dropwhile() to locate the start of the words and iterate from there:
from itertools import dropwhile
print("***** Anagram Finder *****")
word = input("Enter a word: ").lower() + '\n'
with open("EnglishWords.txt") as f_words:
if word in dropwhile(lambda r: not r.startswith("START"), f_words):
print("Yes, {} is in the file".format(word.strip()))
else:
print("Sorry, {} is not in the file.".format(word.strip()))
You can use a boolean :
file = open(“testfile.txt”, “r”)
foundStart = False
for line in file:
if foundStart:
# do something...
elif line == "START":
foundStart = True
I have imported two text files into my program-
f = open("words.txt","r")
words = f.read()
f = open("solved.txt","r")
solved = f.read()
and they are involved in a 'Guess the Word' game I am making.
At the end of the game, the program checks the users answers against the real ones...
print('Checking words...')
sleep(2)
if (words) == (solved):
print('>Well done!')
sleep(1)
print('>All of your answers are right')
else:
print('Not quite, keep trying!')
sleep(1)
menu()
The words text file has an extra carriage return on the end of the string, so no matter what the user makes the words string, it will never be exactly the same as the solved string (with no carriage return on the end), and therefore the user can NEVER win the game.
I HAVE the edit the text files within the program only, so I would like a way to delete the extra carriage return from the end of the words string, so that the user CAN win the game.
Words.txt-
#+/084&"
#3*#%#+
8%203:
,1$&
!-*%
.#7&33&
#*#71%
&-&641'2
#))85
9&330*
Theres an extra space here
Solved.txt-
ACQUIRED
ALMANAC
INSULT
JOKE
HYMN
GAZELLE
AMAZON
EYEBROWS
AFFIX
VELLUM
-Alastair
def getwords(file_name):
with open(file_name) as file:
for word in file:
word = word.strip()
if word: yield word
words = list(getwords("words.txt"))
solved = list(getwords("solved.txt"))
... # do anything with 'words' and 'solved' #...