I am trying to return a word from a text file (so that I can eventually make a game from the word) but right now I get the error
IndexError: string index out of range
this is what my text file looks like
yellow
awesome
barking
happy
dancing
laughing
and this is the code I currently have
import random
def generate_the_word(infile):
for line in infile.readlines():
random_line = random.randrange(line[0], line[len(line) + 1])
print(random_line)
def main():
infile = open("words.txt","r")
generate_the_word(infile)
infile.close
main()
Do I have the wrong idea about indexing?
import random
def generate_the_word(infile):
random_line = random.choice(open(infile).read().split('\n'))
return random_line
def main():
infile = "words.txt"
print(generate_the_word(infile))
main()
Your for loop is iterating over every line in the file and indexing into that line. You should also take advantage of Python's context managers, which take care of opening and closing files for you. What you want is to load all the lines:
with open(infile) as f:
contents_of_file = f.read()
Your second problem is that you aren't properly indexing into those lines with randrange. You want a range between 0 and the max number of lines:
lines = contents_of_file.splitlines()
line_number = random.randrange(0, len(lines))
return lines[line_number]
You also need to import the random module before this will run.
Your whole program would look like:
import random
def generate_the_word(infile):
with open(infile) as f:
contents_of_file = f.read()
lines = contents_of_file.splitlines()
line_number = random.randrange(0, len(lines))
return lines[line_number]
def main():
print(generate_the_word("Filename.txt"))
main()
You should also note that reading the file every time is inefficient; perhaps read it once and then pick lines from that. You could, for instance, read it in the main function and pass its already-read values to the generate_the_word function.
When you use readlines(), you get a list of lines. The random module has a handy method for picking a random element from such iterables which eliminates the need for "manually" dealing with indexing: random.choice(iterable).
All you need is this (no for loop necessary):
def generate_the_word(infile):
return random.choice(infile.readlines())
def main():
infile = open("words.txt","r")
generate_the_word(infile)
infile.close
main()
To avoid the costly operation of reading the file every time you want a single random word, you could also read the file in main and pass the list to generate_the_word instead:
import random
def generate_the_word(word_list):
return random.choice(word_list)
def main():
infile = open("words.txt","r")
lines = infile.readlines()
infile.close()
print generate_the_word(lines)
main()
Related
I'm trying to create a game of hangman. When I try to read the file with a list of words it returns an empty array.
Code:
#Making a game of hangman
import random
def rand_word(file_name):
# Retrieves a random word from a file
f = open(file_name, "r")
for num_lines, words in enumerate(f):
pass
num_lines += 1
print(num_lines)
rand_line = random.randint(1,num_lines)
print (rand_line)
file = f.readlines()
print(file)
f.close()
rand_word("words.txt")
You exhausted the file when looping over it in your for loop, so when you use readlines, you're at the end of the file and there's nothing left to read.
You should read your words in a list first, then choose a random one from the list:
import random
def rand_word(filename):
with open(filename) as f:
words = f.readlines()
word = random.choice(words).strip()
return word
import random
com=input("")
if com.startswith("/tip"):
numlines=sum(1 for line in open("C:\\Users\\Jace\\Desktop\\Python Programs\\Quote\\tip.txt"))-1
randomint=random.randint(0, numlines)
with open("C:\\Users\\Jace\\Desktop\\Python Programs\\Quote\\tip.txt", "r") as f:
i=1
for line in f:
if i==randomint:
break
i+=1
print(line.strip("\n"))
This is the part of the code for my random tips from a file so far. I wish to add another part of code where it adds all strings with any occurrence of the input placed after "/tip ", for example, if I were to type "/tip Hello", it would compile all lines in the text file with "Hello" in the string and do a random.choice() from the list, printing the one chosen. I don't really know where to start with this, any help would be appreciated. Thanks in advance!
You don't have to store all of the lines in a list. You can read the lines, selecting one at random and discarding the rest. This is called "resevoir sampling".
Your code might look like this:
import random
def random_line(iterator):
result = None
for n, item in enumerate(iterator):
if random.randint(0,n) == 0:
result = item
return result
# A random line
with open('tip.txt') as f:
print random_line(f) or "No tip for you!"
# A random line that has 'Hello'
with open('tip.txt') as f:
print random_line(line for line in f if 'Hello' in line) or "nothin!"
As a more special case, this code randomly chooses a matching line from the tips file, but falls back to a random non-matching line if no match exists. It has the advantages of reading the input file exactly once, and not having to store the entire tips file in memory.
import random
def random_line_with_fallback(iterator, match = lambda x: True):
result_match = None
result_all = None
n_match = n_all = 0
for item in iterator:
if match(item):
if random.randint(0, n_match) == 0:
result_match = item
n_match += 1
if random.randint(0, n_all) == 0:
result_all = item
n_all += 1
return (result_match or result_all).strip()
# A random line
with open('tip.txt') as f:
print random_line_with_fallback(f)
# Another way to do a random line. This depends upon
# the Python feature that "'' in line" will always be True.
com = ''
with open('tip.txt') as f:
print random_line_with_fallback(f, lambda line: com in line)
# A random line that has 'Hello', if possible
com = 'Hello'
with open('tip.txt') as f:
print random_line_with_fallback(f, lambda line: com in line)
References:
https://stackoverflow.com/a/23840292/8747
https://en.wikipedia.org/wiki/Reservoir_sampling
I think this is what you want, process each line of a text file, checking if the line has the word you're looking for. If so, add it to a list, and the randomly select one "line" for all possible "lines".
lines = []
with open("tip.txt", "r") as f:
for line in f:
if com in line:
lines.append(line)
print(random.choice(lines))
This is probably something so simple. I'm scripting something to print random lines from a file but it prints one character at a time. Here is the code.
from twython import Twython, TwythonError
import random, time
filename = open('test.txt')
line = random.choice(filename.readlines())
filename.close()
for line in line:
print line
Any help is definitely appreciated. I'm a beginner so it honestly is probably something simple.
The problem here is that random.choice will return a string. And in effect you are iterating over a string. What you should do is call split() after you call random.choice so you end up with a list of words instead of a string. Then your iteration will work as expected.
Also, you really should not iterate like this:
for line in line
Change your iterator:
for word in line
Also, it would be good practice to get used to using context managers when handling files. e.g.:
with open(some_file) as f:
# do file actions here
So, your final solution would look like:
import random
with open('new_file.txt') as f:
line = random.choice(f.readlines()).split()
for word in line:
print(word)
random.choice will return only on element at a time, you have to use shuffle instead:
from twython import Twython, TwythonError
import random, time
filename = open('test.txt')
lines = filename.readlines()
filename.close()
random.shuffle(lines)
for line in lines:
print line
A couple things, first thing is readability:
for line in line
print line #which line do you mean?
Now,
line = random.choice(filename.readlines())
Will just give you a random line in the file, it won't give you all the lines in a random order.
You can shuffle the array with a simple call
import random
filename = open('new_file.txt')
lines = filename.readlines()
random.shuffle(lines)
for line in lines:
print line
You can also keep randomly taking items out of the array until it is empty
import random
filename = open('new_file.txt')
lines = set( filename.readlines() )
while( len(lines) != 0 ):
choice = random.choice(list(lines))
print(choice)
lines.remove(choice)
This answer may be helpful: randomly selecting from array
What i'm trying to do is to take 4 lines from a file that look like this:
#blablabla
blablabla #this string needs to match the amount of characters in line 4
!blablabla
blablabla #there is a string here
This goes on for a few hundred times.
I read the entire thing line by line, make a change to the fourth line, then want to match the second line's character count to the amount in the fourth line.
I can't figure out how to "backtrack" and change the second line after making changes to the fourth.
with fileC as inputA:
for line1 in inputA:
line2 = next(inputA)
line3 = next(inputA)
line4 = next(inputA)
is what i'm currently using, because it lets me handle 4 lines at the same time, but there has to be a better way as causes all sorts of problems when writing away the file. What could I use as an alternative?
you could do:
with open(filec , 'r') as f:
lines = f.readlines() # readlines creates a list of the lines
to access line 4 and do something with it you would access:
lines[3] # as lines is a list
and for line 2
lines[1] # etc.
You could then write your lines back into a file if you wish
EDIT:
Regarding your comment, perhaps something like this:
def change_lines(fileC):
with open(fileC , 'r') as f:
while True:
lines = []
for i in range(4):
try:
lines.append(f.next()) # f.next() returns next line in file
except StopIteration: # this will happen if you reach end of file before finding 4 more lines.
#decide what you want to do here
return
# otherwise this will happen
lines[2] = lines[4] # or whatever you want to do here
# maybe write them to a new file
# remember you're still within the for loop here
EDIT:
Since your file divides into fours evenly, this works:
def change_lines(fileC):
with open(fileC , 'r') as f:
while True:
lines = []
for i in range(4):
try:
lines.append(f.next())
except StopIteration:
return
code code # do something with lines here
# and write to new file etc.
Another way to do it:
import sys
from itertools import islice
def read_in_chunks(file_path, n):
with open(file_path) as fh:
while True:
lines = list(islice(fh, n))
if lines: yield lines
else: break
for lines in read_in_chunks(sys.argv[1], 4):
print lines
Also relevant is the grouper() recipe in the itertools module. In that case, you would need to filter out the None values before yielding them to the caller.
You could read the file with .readlines and then index which ever line you want to change and write that back to the file:
rf = open('/path/to/file')
file_lines = rf.readlines()
rf.close()
line[1] = line[3] # trim/edit however you'd like
wf = open('/path/to/write', 'w')
wf.writelines(file_lines)
wf.close()
I am having problems with opening and using text files as lists in python...I need to use the string values in a text file(50 words in each), three text files...And I need to use a random word from each text file in an order to create an insult each time....(Shakespearian insults for those who know)
import random #Import my random
Column_picker = random.randint(0, 45) #Define my random between 0-50
with open("Column1.txt") as d:
insults1 = list(d)
with open("Column2.txt") as f:
insults2 = list(f)
with open("Column3.txt") as e:
insults3 = list(e)
print("Thou", insults1[], insults2[], insults3[])
That is what I have so far, and I feel really close I just cannot grab the right strings from the list..it either grabs the whole list or just a letter from it....
Use random.choice:
import random
def random_word(filename):
with open(filename) as file:
return random.choice(file.readlines())
filenames = ["file.txt", "another.txt"]
print("Thou " + ' '.join(map(random_word, filenames)))
You could also use linecache.getline(filename, line_number) if you need to get lines multiple times.
I assume each insult is a line in the file, but we can replace readlines with readlines[0].split() if they are space delimited on the first line, and we can add a bit to ignore \n, etc. But the idea is still the same.
import random #Import my random
Column_picker = random.randint(0, 45) #Define my random between 0-50
with open("Column1.txt") as d:
insults1 = d.readlines()
with open("Column2.txt") as f:
insults2 = f.readlines()
with open("Column3.txt") as e:
insults3 = e.readlines()
print("Thou", insults1[Column_picker], insults2[Column_picker], insults3[Column_picker])
definitely better with a funcition:
def random_word(fname):
line_num = random.randint(0, 45)
with open(fname) as f:
lines = f.readlines()
return lines[line_num]
print("Thou",
random_word("Column1.txt"),
random_word("Column2.txt"),
random_word("Column3.txt"))
The last line can even be a little cleaner:
files = ['Column1.txt','Column2.txt','Column3.txt']
insults = [random_word(f) for f in files]
print ( "Thou "+' '.join(insults) )