Udacity python exercise - python

Im coding a madlibs exercise and it is not returning the desired outcome. It should replace the words NOUN and VERB with random verbs and nouns that are defined in the functions in the code.
I have created two test sentences and after running the code I only get the first character of both sentences. I cant think for the life of me why!!
from random import randint
def random_verb():
random_num = randint(0, 1)
if random_num == 0:
return "run"
else:
return "kayak"
def random_noun():
random_num = randint(0,1)
if random_num == 0:
return "sofa"
else:
return "llama"
def word_transformer(word):
if word == "NOUN":
return random_noun()
elif word == "VERB":
return random_verb()
else:
return word[0]
def process_madlib(madlib):
#the finished sentence
processed = ""
#starting point
index = 0
#length to cut from
box_length = 4
#
while index<len(madlib):
#what you cut off from string
frame = madlib[index:index+box_length]
#put to string
to_add = word_transformer(frame)
processed += to_add
if len(to_add) == 1:
index +=1
else:
index +=5
return processed
# your code here
# you may find the built-in len function useful for this quiz
# documentation: https://docs.python.org/2/library/functions.html#len
test_string_1 = "This is a good NOUN to use when you VERB your food"
test_string_2 = "I'm going to VERB to the store and pick up a NOUN or two."
print process_madlib(test_string_1)
print process_madlib(test_string_2)
the outcome is
T
I

Your return is not correctly placed.
The return processed is inside the while loop - so after the first iteration of your while loop you will always return the value - which is just the first letter in the sentence.
You need to place it outside.
def process_madlib(madlib):
#the finished sentence
processed = ""
#starting point
index = 0
#length to cut from
box_length = 4
#
while index<len(madlib):
#what you cut off from string
frame = madlib[index:index+box_length]
#put to string
to_add = word_transformer(frame)
processed += to_add
if len(to_add) == 1:
index +=1
else:
index +=5
return processed # <---- THIS IS WHAT WAS CHANGED
This gives the output:
This is a good sofato use when you runyour food
I'm going to kayakto the store and pick up a llamaor two.

Related

Printing out Words for a Python Word Game that uses Parallelism/Multiprocessing

I am working on a Multiprocessing Word game with Python. And I need some help with getting the program to print words to the screen. The original code, that i started out with, before I added code for Multiprocessing, was able to print words out from the screen. I'm using a dictionary, where each words is a 3 letter word. The goal of the game is to, ask "What is the 1st word" & "What is the 2nd word. And then, the program changes 1 letter at a time, until it reaches the 2nd word. I will include the original code, that is able to print words from the screen, somewhere in the comments, if i can.
Here is the link to the dictionary that I am using. But, u can also use a dictionary of ur choice. text
Below is the fist part of my code. vvvvvvvvvvvvvv
```python
from multiprocessing import Process, Queue
class node:
def __init__(self, word):
self._word = word
self._neighbors = []
self._status = 0
self._discoveredby = 0
def getWord(self):
return self._word
def getNeighbors(self):
return self._neighbors
def addNeighbor(self, neighbor_index):
self._neighbors.append(neighbor_index)
def isUnseen(self):
if self._status == 0:
return True
else:
return False
def isSeen(self):
if self._status == 1:
return True
else:
return False
def setUnseen(self):
self._status = 0
def setSeen(self):
self._status = 1
def discover(self, n):
self._discoveredby = n
def discovered(self):
return self._discoveredby
#Get starting and ending word
word1 = input("What is the starting word? ")
word2 = input("What is the ending word? ")
```python
Also, here is the second part of the code for the word Game. It does not have any errors as far as I know. But, what i'm wondering is.
Why does it not print out the words to the screen?
The Original code that I started out with, before modifying it to use Multiprocessing, was able to print words to the screen. I can include my original code, in the comments if u want to see it.
And here is the Dictionary again text
```python
if __name__ == '__main__':
#Read in the words from a dictionary
words = []
dict = open("Word Game Text.txt", 'r')
for line in dict:
word = node(line.strip())
words.append(word)
def findlinks(words, q, starti, endi):
for i in range(starti, endi):
for j in range(i + 1, len(words)):
#compare word i and word j
if compareWords(words[i].getWord(), words[j].getWord()):
q.put((i, j)) #addLink(words, i, j)
q = Queue()
process_list = []
for i in range(0,len(words)-100,100):
p = Process(target=findlinks, args=(words,q, i, i+100))
process_list.append(p)
p = Process(target=findlinks, args=(words, q, i+100, len(words)))
process_list.append(p)
for p in process_list:
p.start()
while not q.empty():
i, j = q.get()
addLink(words, i, j)
for p in process_list:
p.join()
while not q.empty():
i, j = q.get()
addLink(words, i, j)
index1 = -1
index2 = -1
for i in range(len(words)):
if words[i].getWord() == word1:
index1 = i
if words[i].getWord() == word2:
index2 = i
if index1 == -1:
print(word1,"was not in the dictionary. Exiting.")
exit(0)
if index2 == -1:
print(word2,"was not in the dictionary. Exiting.")
exit(0)
path = BFS(words, index1, index2)
#Report the chain
if path == []:
print("There was no chain between those words, in my dictionary")
else:
for index in path:
print(words[index].getWord())
#print(words[index].getWord())
```python

(Python3) - Random number inserted at the end of only 1 word in a string of many words

I am trying to make a random word/phrase generator that is like the one that bitwarden has (in python3). But the issue I am running into and need some help with is the addition of 1 number at the end of 1 of the words that is shown.
Something like this Referee-Outrank-Cymbal-Cupping-Cresting-Fiber7-Expensive-Myth-Unveiling-Grasp-Badland-Epiphany-Simplify-Munchkin-Pastrami-Spiffy-Gladly-Skeptic-Retouch-Buckskin
What is very important here is that the number is "random" and the word it is attached to is "random".
Code I have written so far:
Word list I am using is https://svnweb.freebsd.org/csrg/share/dict/words?view=co&content-type=text/plain but without ' in any of the words.
#pycryptodome==3.15.0
from Crypto.Random import random
import beaupy
import os
def clear():
os.system('clear||cls')
def main():
while True:
try:
number = int(beaupy.prompt("How many words?: "))
except ValueError as e:
print(f'Oops! Something went wrong.\nError: {e}\n\n')
input('Press "enter" to continue...')
clear()
continue
if number > 20 or number < 3:
print("20 words is the maximum number of words you can use. And 5 words is the minimum.\n\n")
input('Press "enter" to continue...')
clear()
else:
break
cwd = os.getcwd()
word_path = f"{cwd}/words.txt"
with open(word_path, 'r') as fh:
words = fh.read().lower()
word_list = words.splitlines() #list of words
sep = beaupy.prompt('Line separator? (leave empty for default "-"): ')
if sep == '' or sep == ',':
sep = '-'
#Returns True or False. Basically Yes or No?
if beaupy.confirm("Capitalize?"):
"""Make list of words with the first letter capitalized."""
c_lst = []
for i in word_list:
c_lst.append(i.title())
capital_words = f'{sep}'.join(random.choice(c_lst) for _ in range(number))
else:
default_words = f'{sep}'.join(random.choice(word_list) for _ in range(number))
if beaupy.confirm("Number?"):
rn_num = random.randint(0, 9) # <-- Get a random number to be used with only 1 of the words defined in capital_words or default_words below.
#I don't know what to do here... but I need to have a version with the number and one without. (default)
if __name__ == '__main__':
clear()
main()
I am not exactly familiar with string manipulation and searching for answers online just isn't giving me any help with the very specific thing I'm trying to do. All I want is for 1 word in the resulting string to have a "random" number attached to it.
I don't know if I need to re order my code and have it be done a different way. I am having such a headache with this. Any help would be great.
Edit#1
Additional and unrelated note, If anyone knows of a better word list to use, please let me know!
If I am understanding correctly, here is a solution:
#Returns True or False. Basically Yes or No?
capital_words = ''
default_words = ''
if beaupy.confirm("Capitalize?"):
"""Make list of words with the first letter capitalized."""
c_lst = []
for i in word_list:
c_lst.append(i.title())
capital_words = f'{sep}'.join(random.choice(c_lst) for _ in range(number))
else:
default_words = f'{sep}'.join(random.choice(word_list) for _ in range(number))
if beaupy.confirm("Number?"):
rn_num = random.randint(0, 9) # <-- Get a random number to be used with only 1 of the words defined in capital_words or default_words below.
#I don't know what to do here... but I need to have a version with the number and one without. (default)
word_index = random.randint(0, number - 1) # Get random index that is in the word list
if default_words != '':
word_with_number = default_words.split(sep)
else:
word_with_number = capital_words.split(sep)
word_with_number[word_index] = word_with_number[word_index] + str(rn_num)
word_with_number = sep.join(word_with_number)
print(word_with_number)
if default_words != '':
print(default_words)
else:
print(capital_words)
OUTPUT:
detroit-elide-windbag-purge-tort-mortician-codex7-annex-fairy-suntanning
detroit-elide-windbag-purge-tort-mortician-codex-annex-fairy-suntanning
With some help from AnonymousFrog. I was able to get my code working.
The following is the now working code.
from Crypto.Random import random
import beaupy
import os
def clear():
os.system('clear||cls')
def main():
while True:
try:
number = int(beaupy.prompt("How many words?: "))
except ValueError as e:
print(f'Oops! Something went wrong.\nError: {e}\n\n')
input('Press "enter" to continue...')
clear()
continue
if number > 20 or number < 3:
print("20 words is the maximum number of words you can use. And 5 words is the minimum.\n\n")
input('Press "enter" to continue...')
clear()
else:
break
cwd = os.getcwd()
word_path = f"{cwd}/words.txt"
with open(word_path, 'r') as fh:
words = fh.read().lower()
word_list = words.splitlines() #list of words
sep = beaupy.prompt('Line separator? (leave empty for default "-"): ')
if sep == '' or sep == ',':
sep = '-'
#Returns True or False. Basically Yes or No?
capital_words = ''
default_words = ''
if beaupy.confirm("Capitalize?"):
"""Make list of words with the first letter capitalized."""
c_lst = []
for i in word_list:
if len(i) < 3 or len(i) > 9:
pass
else:
c_lst.append(i.title())
cap = True
capital_words = f'{sep}'.join(random.choice(c_lst) for _ in range(number))
else:
cap = False
default_words = f'{sep}'.join(random.choice(word_list) for _ in range(number))
if beaupy.confirm("Number?"):
num = True
rn_num = random.randint(0, 9) # <-- Get a random number to be used with only 1 of the words defined in capital_words or default_words below.
word_index = random.randint(0, number - 1) # Get random index that is in the word list
if default_words != '':
word_with_number = default_words.split(sep)
else:
word_with_number = capital_words.split(sep)
word_with_number[word_index] = word_with_number[word_index] + str(rn_num)
word_with_number = sep.join(word_with_number)
else:
num = False
if cap == True and num == False:
print(capital_words)
if cap == False and num == False:
print(default_words)
if num == True:
print(word_with_number)
Thanks for the help!
(if anyone knows of a better word list to use, feel free to let me know)

Python | Returns none when doing a while loop

# Let's put it all together. Write code for the function process_madlib, which takes in
# a string "madlib" and returns the string "processed", where each instance of
**# "NOUN" is replaced with a random noun and each instance of "VERB" is
# replaced with a random verb. You're free to change what the random functions
**# return as verbs or nouns for your own fun, but for submissions keep the code the way it is!****
from random import randint
def random_verb():
random_num = randint(0, 1)
if random_num == 0:
return "run"
else:
return "kayak"
def random_noun():
random_num = randint(0,1)
if random_num == 0:
return "sofa"
else:
return "llama"
def word_transformer(word):
if word == "NOUN":
return random_noun()
elif word == "VERB":
return random_verb()
else:
return word[0]
def process_madlib(text):
proc =""
lenght = len("NOUN")
i=0
while text[i:i+lenght] !='':
i +=1
if text[i:1+lenght] == "NOUN":
proc= text[i:-1] + word_transformer("NOUN") + text[i+lenght:]
return proc
**
**# you may find the built-in len function useful for this quiz
# documentation: https://docs.python.org/2/library/functions.html#len**
**
test_string_1 = "ds NOUN ds"
test_string_2 = "I'm going to VERB VERB to the store and pick up a NOUN or two."
print process_madlib(test_string_1)
print process_madlib(test_string_2)
Always Return none , if i tested it manually and change "i" all look good
edit : adding code ......
your can read the instruction in the comments
Your code has a few issues with the variable you're using in the loop, specifically you should be using lenght + i instead of lenght + 1. Also, you're incrementing i in the wrong spot.
Here's a version that works:
def process_madlib(text):
proc = ""
lenght = len("NOUN")
i = 0
while text[i:lenght + i] != '':
if text[i:lenght + i] == "NOUN":
proc = text[i:-1] + word_transformer("NOUN") + text[i + lenght:]
return proc
i += 1
return text
test_string_1 = "NOUN ds"
test_string_2 = "I'm going to VERB to the store and pick up a NOUN or two."
print(process_madlib(test_string_1))
print(process_madlib(test_string_2))
It looks like you misspelled "lenght". It should be "length".
Aside from that, what I think you are trying to use is len(i).
Here is the code in the middle.
while text[i:len(text)+1] !='':
i +=1
if text[i:len(text)+1] == "NOUN":
proc= text[i:-1] + word_transformer("NOUN") + text[i+len(text):]
return proc
edited based on Aran-Fey's comment.

Repeatedly replacing parts of a string in a loop

I created a HTML text cleaner, which deletes data between tags.
It's working fine on one iteration, but not in a loop.
The problem is, I cannot save newhtml as a variable due to Python's string immutability.
So, my loop is only working for the last iteration of the function return.
What would be the best practice in such a situation?
def find_all(a_str, sub):
start = 0
while True:
start = a_str.find(sub, start)
if start == -1: return
yield start
start += len(sub) # use start += 1 to find overlapping matches
def replace_string(index1, index2, mainstring):
replacementstring = ''
return mainstring.replace(mainstring[index1:index2], replacementstring)
def strip_images(html):
begin_indexes = list(find_all(html, '<DESCRIPTION>GRAPHIC'))
end_indexes = list(find_all(html, '</TEXT>'))
for i in range(len(begin_indexes)):
if begin_indexes[i] > end_indexes[i]:
end_indexes.pop(0)
else:
if len(begin_indexes) == len(end_indexes):
break
for i in range(len(begin_indexes)):
#code problem is here--
newhtml = replace_string(begin_indexes[i],end_indexes[i], html)
if i == len(begin_indexes) - 1:
return newhtml
#code only returns one iteration
var = strip_images(html)
print var
Your current issue is that html never changes within the loop. So, your input will always be for the first iteration, regardless of the length of the lists.
The solution here follows these steps
Assign the string to the original value before the loop
Edit within the loop, passing in the current content, returning a replaced string
Return from the function after the loop
newhtml = html
for begin, end in zip(begin_indexes, end_indexes):
newhtml = replace_string(begin, end, newhtml)
return newhtml
Got it working, here's the code snippet. It's not pretty but it's doing the job of removing text between those two tags:
def find_all(a_str, sub):
start = 0
while True:
start = a_str.find(sub, start)
if start == -1: return
yield start
start += len(sub) # use start += 1 to find overlapping matches
def strip_images(html):
begin_indexes = list(find_all(html, '<DESCRIPTION>GRAPHIC'))
end_indexes = list(find_all(html, '</TEXT>'))
for i in range(len(begin_indexes)):
if begin_indexes[i] > end_indexes[i]:
end_indexes.pop(0)
else:
if len(begin_indexes) == len(end_indexes):
break
newhtml = html
begin_indexes2 = begin_indexes[::-1]
end_indexes2 = end_indexes[::-1]
for i in range(len(begin_indexes2)):
#for i, value in enumerate(begin_indexes,0):
#end_indexes.reset_index(drop=True)
newhtml = list(newhtml)
del newhtml[begin_indexes2[i]:end_indexes2[i]]
if i == len(begin_indexes2) - 1:
str1 = ''.join(newhtml)
return str1

"None" included in program output... why?

i've searched the forum and found similar questions, but no luck in solving my problem.
My code is designed to swap every two letters of each word using recursion and print the result. For words with an even amount of letters, the word "None" is included in the output and i don't know how to fix...
here's the code:
def encryptLine(line, count):
headline = line[count:]
if length(headline) > 0:
if count == length(line) - 1:
new = headline
return new
elif count <= length(line):
new = head(tail(headline)) + head(headline)
new = new + str(encryptLine(line, count+2))
return new
print(encryptLine('abcd', 0))
the output for 'abcd' is badcNone, which is correct except for the word None. the output for 'abcde' is 'badce', which is correct...
thanks in advance for your help!
Add return "" to the function definition, that is
def encryptLine(line, count):
headline = line[count:]
if length(headline) > 0:
if count == length(line) - 1:
new = headline
return new
elif count <= length(line):
new = head(tail(headline)) + head(headline)
new = new + str(encryptLine(line, count+2))
return new
return ""
Otherwise, the function will return None if length(headline) > 0 does not hold.
None is here because your function return nothing.
There is 1 case where you return nothing it is
if length(headline) <= 0:
In Python, if there is no return to a function and you try to access to a return value, the value will be None.

Categories

Resources