I have been trying to create a program that lets users name, write and save documents, here is what I have come up with so far:
doc_name = str(input("Document Name: "))
end = ""
for line in iter(input, end):
document = "\n".join(iter(input, end))
pass
try:
savefile = open("/home/" +doc_name+ ".txt", "w")
savefile.write(x)
savefile.close()
print("Document - " +doc_name+ "\nSuccessfully saved.\n\n")
except:
print("An error occurred.\nUnable to save document.\n\n")
The 'for loop' I have used was from the following page:
Raw input across multiple lines in Python but I am unsure how to use the input from this loop, so I am able to save it to a textfile.
I need the input in this line of code in the place of x:
savefile.write(x)
I am using Python 3.2.3 for this program (if that helps?).
I would like to know how the user input entered during the for loop can be stored in a varible and then used at some other point in the program.
Thanks.
doc_name = input("Document Name: ") # don't need to cast to str
end = ""
result = [] # I recommend initializing a list for the lines
for line in iter(input, end): # you only need this single input call
result.append(line) # add each line to the list
try:
# using "with" in this manner is guaranteed to close the file at the end
with open("/home/" +doc_name+ ".txt", "w") as savefile:
for line in result: # go through the list of lines
# write each one, ending with a newline character
savefile.write(line + '\n')
except IOError:
print("An error occurred.\nUnable to save document.\n\n")
else: # print this if save succeeded, but it's not something we want to "try"
print("Document - " +doc_name+ "\nSuccessfully saved.\n\n")
You only need to use pass when Python expects statements (such as in an indented block) but you have no statements for it to execute - it's basically a placeholder. The common use is when you want to define your program's functions (e.g., def myfunction(a, b):) but you don't have the actual content for them yet.
Related
for i in range(0,5):
f = open("StudentRecords.txt", "a")
try:
f.write(input("Name: ")+"\n")
f.write(str(int(input("ID: ")))+"\n")
f.write(str(float(input("GPA: ")))+"\n")
except ValueError:
print("Error: You entered a String for ID or GPA.")
f.close()
Here for example if I tried to write a string for GPA, I will catch the error and the program will move on, but the Name and ID of the same iteration will still be written
I want it to only write if all the 3 data are valid.
As the comments said, the best approach is to validate all the data before writing anything. But if you really need to undo, you can do it by saving the file position before each record, seeking back to it, and truncating to remove everything written after.
And rather than reopening the file for each record, you should open it once before the loop. Use with to close it automatically when the block is finished.
with open("StudentRecords.txt", "w") as f:
for i in range(0,5):
try:
filepos = f.tell()
f.write(input("Name: ")+"\n")
f.write(str(int(input("ID: ")))+"\n")
f.write(str(float(input("GPA: ")))+"\n")
except ValueError:
print("Error: You entered a String for ID or GPA.")
f.seek(filepos)
f.truncate()
The simple solution is to save the inputs in variables first, and then save to file.
for i in range(0,5):
f = open("StudentRecords.txt", "a")
try:
name = input("Name: ")+"\n"
ID = str(int(input("ID: ")))+"\n"
GPA = str(float(input("GPA: ")))+"\n"
f.write(name + ID + GPA)
except ValueError:
print("Error: You entered a String for ID or GPA.")
f.close()
That being said, I would suggest updating the code a little more:
for i in range(0,5):
name = input("Name: ") + "\n"
try:
ID = str(int(input("ID: "))) + "\n"
GPA = str(float(input("GPA: "))) + "\n"
with open("StudentRecords.txt", "a") as f:
f.write(name + ID + GPA)
except ValueError:
print("Error: You entered a String for ID or GPA.")
Using with means you won't have to deal with the f.close(), among other things, and so you won't forget it. And since the name = ... line doesn't seem to need a try-except block, we can move it outside.
Others have shown you a way to validate your data, but right now the program just stops if the user makes a mistake. You really want some way for them to correct their error and continue.
To put this in your main routine would require a separate loop and try/except structure for each number, which isn't too bad right now with two values, but gets unwieldy as you add more.
So instead of repeating ourselves, let's write a function that repeats until the user enters a valid number. We can pass in the type of number we want (int or float).
def inputnum(prompt, T=float):
while True:
try:
return T(input(prompt))
except ValueError:
print(">>> You entered an nvalid number. Please try again.")
Then call that function to get your numbers (combined with some other small improvements):
with open("StudentRecords.txt", "a") as f:
for i in range(5):
name = input("Name: ")
ID = inputnum("ID: ", int)
GPA = inputnum("GPA: ", float)
f.write(f"{name}\n{ID}\n{GPA}\n")
Im new to python and Im trying to search a text file for a particular string, then output the whole line which contains that string. However, I want to do this as two separate files. Main file contains the following code;
def searchNoCase():
f = open('text.txt')
for line in f:
if searchWord() in f:
print(line)
else:
print("No result")
f.close()
def searchWord(stuff):
word=stuff
return word
File 2 contains the following code
import main
def bla():
main.searchWord("he")
Im sure this is a simple fix but I cant seem to figure it out. Help would be greatly appreciated
I don't use Python 3 so I need to check exactly what changed with __init__.py but in the meantime, create an empty script with that name in the same directory as the following files.
I've tried to cover a few different topics for you to read up on. For example, the exception handler is basically useless here because input (in Python 3) always returns a string but it's something you would have to worry about.
This is main.py
def search_file(search_word):
# Check we have a string input, otherwise converting to lowercase fails
try:
search_word = search_word.lower()
except AttributeError as e:
print(e)
# Now break out of the function early and give nothing back
return None
# If we didn't fail, the function will keep going
# Use a context manager (with) to open files. It will close them automatically
# once you get out of its block
with open('test.txt', 'r') as infile:
for line in infile:
# Break sentences into words
words = line.split()
# List comprehention to convert them to lowercase
words = [item.lower() for item in words]
if search_word in words:
return line
# If we found the word, we would again have broken out of the function by this point
# and returned that line
return None
This is file1.py
import main
def ask_for_input():
search_term = input('Pick a word: ') # use 'raw_input' in Python 2
check_if_it_exists = main.search_file(search_term)
if check_if_it_exists:
# If our function didn't return None then this is considered True
print(check_if_it_exists)
else:
print('Word not found')
ask_for_input()
I want to download new tweets from a particular user and filter with a few other rules. How do I cross reference the tweet ID from the tweet I am handling with what ID's are in the tweetid.txt file to avoid duplicating what I am saving in the NRE_tweet file?
This is what I have written so far that is producing duplicates.
i = 0
for tweet in NRE_tweets:
tweet_ids = open('tweetid.txt', 'a+')
if NRE_tweets[i]['in_reply_to_screen_name'] is None:
if NRE_tweets[i]['id_str'] not in tweet_ids.readlines():
print("adding tweet " + str(NRE_tweets[i]['id_str']))
info_wanted.append(NRE_tweets[i]['text'])
info_wanted.append(NRE_tweets[i]['id_str'])
info_wanted.append(NRE_tweets[i]['created_at'])
NRE_file = open('NRE.txt', 'a')
NRE_file.write(str(info_wanted) + '\n')
NRE_file.close()
append_tweet_ids = open('tweetid.txt', 'a')
append_tweet_ids.write(NRE_tweets[i]['id_str'] + '\n')
append_tweet_ids.close()
tweet_ids.close()
info_wanted = []
i += 1
EDIT: Thanks for advice, working code is now sorted. There is a few things I can do to make it cleaner, but for now... It works.
NRE_tweets = t.statuses.user_timeline(screen_name='NRE_northern')
i = 0
NRE_file = open('NRE.txt', 'a')
openFile = shelve.open('tweetid')
try:
loadIDs = openFile['list_id']
print("list_id's loaded")
except:
print("exception entered")
loadIDs = []
for tweet in NRE_tweets:
if NRE_tweets[i]['in_reply_to_screen_name'] is None: # check that tweet isn't a reply
if NRE_tweets[i]['id_str'] in loadIDs:
print(str(NRE_tweets[i]['id_str']) + ' already stored')
else:
print("adding " + str(NRE_tweets[i]['id_str']))
# added wanted elements to a list
info_wanted.append(NRE_tweets[i]['text'])
info_wanted.append(NRE_tweets[i]['id_str'])
info_wanted.append(NRE_tweets[i]['created_at'])
# added list to txt file
NRE_file.write(str(info_wanted) + '\n')
loadIDs.append(NRE_tweets[i]['id_str'])
openFile['list_id'] = loadIDs
info_wanted = []
i += 1
print(openFile['list_id'])
NRE_file.close()
openFile.close()
Don't use if x is None: in your code, unless there's a chance that x is literally None. Because only None is None and everybody else (0, empty iterables, etc) are fakers :) Instead, you should use if not x.
readlines() returns the lines in the file, including the line ending \n for each line. So you should write if (NRE_tweets[i]['id_str'] + '\n') not in tweet_ids.readlines():
Like you've been advised in a comment, open the file once before your for loop and close after the for loop. Also consider using the shelve module (or sqlite3) for this; it'll make handling the data a lot easier.
EDIT:
Also I notice you opened tweetid.txt twice without closing in between. Theres no need for the second open() inside the IF block. You can simply call write() using the first file handle, in order to add the new ID to the file. You should also call readlines() outside the loop and save it to a list which you then use in the for loop header, because, with your new code structure, subsequent calls to readlines() will return an empty string as the file has been exhausted. So when you find a new ID, you append it to this list, as well as call write() to add the ID to tweetid.txt.
An alternative is that you open the file in read mode at first, call readlines() and save the result to a list, close the file. Start the loop and perform all your operations on the list; add new IDs, delete, whatever. At the end of the loop, you re-open tweetid.txt in write mode and write the lists contents to the file; it will overwrite the old contents. Use this method if you could be adding a lot of new IDs.
Structure your code so that you only open files once, operate on them and finally close them.
This question already has answers here:
How to read multiple lines of raw input?
(16 answers)
Closed 6 years ago.
I want to write a program that gets multiple line input and work with it line by line. Why isn't there any function like raw_input in Python 3?
input does not allow the user to put lines separated by newline (Enter). It prints back only the first line.
Can it be stored in a variable or even read it to a list?
raw_input can correctly handle the EOF, so we can write a loop, read till we have received an EOF (Ctrl-D) from user:
Python 3
print("Enter/Paste your content. Ctrl-D or Ctrl-Z ( windows ) to save it.")
contents = []
while True:
try:
line = input()
except EOFError:
break
contents.append(line)
Python 2
print "Enter/Paste your content. Ctrl-D or Ctrl-Z ( windows ) to save it."
contents = []
while True:
try:
line = raw_input("")
except EOFError:
break
contents.append(line)
In Python 3.x the raw_input() of Python 2.x has been replaced by input() function. However in both the cases you cannot input multi-line strings, for that purpose you would need to get input from the user line by line and then .join() them using \n, or you can also take various lines and concatenate them using + operator separated by \n
To get multi-line input from the user you can go like:
no_of_lines = 5
lines = ""
for i in xrange(no_of_lines):
lines+=input()+"\n"
print(lines)
Or
lines = []
while True:
line = input()
if line:
lines.append(line)
else:
break
text = '\n'.join(lines)
input(prompt) is basically equivalent to
def input(prompt):
print(prompt, end='', file=sys.stderr, flush=True)
return sys.stdin.readline()
You can read directly from sys.stdin if you like.
lines = sys.stdin.readlines()
lines = [line for line in sys.stdin]
five_lines = list(itertools.islice(sys.stdin, 5))
The first two require that the input end somehow, either by reaching the end of a file or by the user typing Control-D (or Control-Z in Windows) to signal the end. The last one will return after five lines have been read, whether from a file or from the terminal/keyboard.
Use the input() built-in function to get a input line from the user.
You can read the help here.
You can use the following code to get several line at once (finishing by an empty one):
while input() != '':
do_thing
no_of_lines = 5
lines = ""
for i in xrange(5):
lines+=input()+"\n"
a=raw_input("if u want to continue (Y/n)")
""
if(a=='y'):
continue
else:
break
print lines
I need to search for something in a tab delimited text file. The user is supposed to input both the file and the thing that needs searching for. The programme is then supposed to return the whole line that the user inputted word is in. I have got two models so far because I've been coming at this problem from different angles. The first programme goes as follows:
import csv
searchfile = raw_input ('Which file do you want to search? ')
try:
input_file = open (searchfile, 'rU')
except:
print "Invalid file. Please enter a correct file"
csv_file_object = csv.reader(open(searchfile, 'rb'))
header = csv_file_object.next()
data=[]
for row in csv_file_object:
data.append(row)
searchA = raw_input ('which author?')
author_search = data[0::,0] == searchA
if author_search in searchfile:
print author_search
The problem with the first programme is that this error pops up:
TypeError: list indices must be integers, not tuple
I therefore attempted this method:
import csv
searchfile = raw_input ('Which file do you want to search? ')
try:
input_file = open (searchfile, 'rU')
except:
print "Invalid file. Please enter a correct file"
with open(searchfile) as f:
reader = csv.reader(f, delimiter="\t")
d = list(reader)
searchtype = raw_input ('Search on author or journal/conference or [Q = quit]')
if searchtype == 'author':
searchdataA = raw_input ("Input author name")
if searchdataA in input_file:
print line
elif searchtype == 'journal' or 'conference' or 'journal/conference':
searchdataJ = raw_input ("input journal/conference name")
if searchdataJ in d:
print line
elif searchtype == 'Q':
print "Program left"
else:
print "please choose either author or journal/conference"
This is unable to get beyond inputting the search parameters.
Any help on where to go with either programme would be much appreciated, or if I'm completely on the wrong track then links to useful material would be great.
I think you're making this a bit more complicated than it needs to be. Since you want to print the whole line that the target word appeared on, you don't really need the CSV module. You're not doing any of the sophisticated parsing it is capable of.
searchfile = raw_input ('Which file do you want to search? ')
searchA = raw_input ('which author?')
with open(searchfile) as infile:
for line in infile:
if searchA in line:
print(' '.join(line.split()))
break # remove this if you want to print all matches instead of
# just the first one
Notice that in the when printing the line, I first split the line (which splits on whitespace by default), then rejoin the fields with two spaces between them. I think doing something like this would be a good way to go for you since you're printing tab-separated fields on the console. Reducing that extra space will make your prints a bit easier to read, but using two spaces still makes it easy to distinguish the columns from each other.
You can generalize it by prompting your user for any search term, instead of specifying "author". This may be the way to go, since your second code snippet suggests that you may want to search for other fields, like "journal" or "conference":
target_term = raw_input("Which term or phrase would you like to find?")
Since this method searches in and prints the entire line, there's no need to deal with the separate columns and different kinds of search terms. It just looks at the whole row at once and prints a matching line.
Since you are not really using a different search method, depending on if you are searching for author, journal, conference or journal/conference. So you could actually do a full text search on the line. Therefore it is wise to collect all data you need from user BEFORE processing file, so you can output just the matching lines. If user passes a rather large CSV file, then your way would take up far too much memory.
with open(searchfile, 'r') as f:
for line in f:
if line.find(searchA) > -1:
print line
This way you are looping through the file as fast as possible and prints out all matching lines.
The .find() function returns the index to where in the string he found the match and otherwise -1 if the string was not found. So from the value you could "estimate" on where the match was made, but if you really want to differentiate between author, journal, etc. then you will have to split the line. In my sample i will assume the author field to be the sixth field in the CSV line:
with open(searchfile, 'r') as f:
for line in f:
fields = line.split("\t")
if len(fields) > 5: # check length of fields array
if fields[5].find(searchA) > -1: # search straight in author field
print line # return full line
why not simply
fname = raw_input("Enter Filename")
author = raw_input("Enter Author Name:")
if author in open(fname,"rb").read():
print "match found"
if you want to see the lines you could do
print re.findall(".*%s.*"%(author),open(fname,"rb").read())
as people point out it is better form to do
with open(fname,"rb") as f:
data = print re.findall(".*%s.*"%(author),f.read())
although in CPython it will be garbage collected immediatly so its not really a problem....
The first thing that came to my mind is simply:
def check_file(file_name, author_name):
with open(file_name) as f:
content = f.readlines()
for line in content:
if author_name in line:
print "Found: ", line
Hope it can be useful.