I'm doing a database using txt files in which the data is stores like this: idTheme|Name|Hours.
For example: 45|Object Oriented Programming|12
I need to print the line of text with the idTheme I'm given, so I did this:
print("Give me the ID")
id_search = input("> ")
for line in file:
for x in line:
if id_search != x:
break
else:
print(line)
break
Since the ID is always the first character in each line I thought thst would work.
Problem is, this only works when the ID is 1 character long.
I was thinking on putting the info on a list and using a split("|") to divide it but that would put all the info in the list, not only the IDs.
Any suggestions are apreciated.
You could use split as you said and just use index 0 to get the ID.
for line in file:
id = line.split("|")[0]
if id_search == id:
print(line)
You can invert your if statement so if the id is equal to the search term it prints the line, otherwise nothing happens. You also avoid looping through the entire line.
You can use somethign like:
with open("text.txt") as f:
lines = [x.strip() for x in list(f) if x]
print("Give me the ID")
id_search = input("> ").strip()
if id_search:
for line in lines:
id, name, otherid = line.split("|")
if id_search == id:
print(line)
break
Demo
Related
So I want to make this script look for a word, which you can determine, and its line number. I want it to print out the text in this line and the two following ones. How do I code the last part (print the next three lines)?
def search_passwords():
file = open("D:\\Libaries\\Documents\\resources_py\\pw.txt", "r")
print()
search = input("Enter service: ")
print()
for line in file:
if search in line:
print(the next three lines)
There are some corner cases that you did not mention.
What if multiple lines have the searching word? What is your expected behavior?
What if the line right after the matching line has the searching word?
How large is the file and could you load it in memory?
If there's only one matching, or there won't be any matching in the lines you print right after, then you can use a single counter
def search_passwords():
file = open("D:\\Libaries\\Documents\\resources_py\\pw.txt", "r")
print()
search = input("Enter service: ")
print()
counter = 0
for line in file:
if counter > 0:
counter -= 1
print(line)
if search in line:
counter = 2
print(line)
However, this will double print the lines if the following lines containing the searching word. You can of course make the second if elif, but then it will just ignore the following matching pattern.
And, if you only need the first or only appearance, you should break out of the loop once you print everything, not read the whole file.
Just like I said, you need to know the expected behavior and the requirement better, to write a solid program.
There could be a better solution but this is a bit more flexible with a nigher amount of following rows.
def search_passwords():
file = open("D:\\Libaries\\Documents\\resources_py\\pw.txt", "r")
print()
search = input("Enter service: ")
print()
counter = 3
found = False
for line in file:
if search in line:
found = True
if found:
if counter > 0:
counter -= 1
print(line, counter)
if counter == 0:
break
Yet another approach with not found error handling:
with open('file.txt', 'r') as f:
lines = [line.strip() for line in f.readlines()]
try:
i = lines.index(input('Enter service: '))
for j in range(i, i+3):
try:
print(lines[j])
except IndexError:
pass
except ValueError:
print('Service not found!')
I have a file with data about students such as their name, address, grades, etc. I created a function that would delete a whole line from a text file based on a student's First Name and Last Name. This function worked correctly. However, afterward, I decided to update it so that if the user entered a name that was not in the file it would print: Student not found. However, now even, if the user types in a name that is in the file it still prints: student not found...
Here is my code:
def delete_a_record(filename):
x=input("Remove First Name:")
y=input("Remove Last Name:")
with open(filename, "r") as f:
lines = f.readlines()
with open(filename, "w") as f:
for i in lines:
t=i.split()
if t[0]!=x and t[1]!=y:
f.write(i)
elif x or y not in t:
print("Student Not Found")
f.close()
delete_a_record("mytextfile.txt")
Could someone explain to me why?
For what I undestood(correct me if I'm wrong), I guess there is two issues in your logic.
If you mean to test if both x and y are not in t you should test it separatelly, like:
if t[0]!=x and t[1]!=y:
f.write(i)
elif x not in t and y not in t:
print("Student Not Found")
The way it is now, if x is not None, the condition elif x or ... will always return true because x evaluates to True.
If you want to check if the student is not in the entire file, I think you should not be testing this for each line you read. Since you don't know in which line the student might be, maybe you could reorganize your code to process the whole file first before testing if the student was not found.
Probably because you are iterating line by line, so even if the name is in the .txt file every time the name doesn't match the current line it will print "Student Not Found". You need to rewrite you function so that the print statement is only made when the lines have been exhausted and the name has not been found.
If You Want to Use Your Function And Search In That (You Don't Want to Change Your Function) You Can Put Your Data In A List And Search In That List Like Below Code:
list=['f_Name = Lorem','l_Name = Ipsum']
if "f_Name = "+x in list or "l_Name = "+y in list:
print("True")
else:
print("Student Not Found")
I am trying to print a specific line from the file "Scores", which is option B. This is my code:
print("Option A: Show all scores\nOption B: Show a record\nOption Q: Quit")
decision = input("Enter A, B, C or Q: ")
myFile = open("Scores.txt", "rt")
if decision == "A":
record = myFile.read()
print(record)
myFile.close()
elif decision == "B" or decision == "b":
playerName = input("Enter a player name to view their scores: ")
record = myFile.read()
answer = record.find(playerName)
for line in answer:
print(line)
elif decision == "Q" or decision == "q":
exit
I went for Option B, then I entered a player name that holds the score of the player, but it throws this error message:
line 12, in <module>
for line in answer():
TypeError: 'int' object is not callable
A few cents from my side :
file = open("file")
lines = file.readlines()
for line in lines:
if playername in line:
print line
file.close()
Hope it works!
find() method returns a positive index if it succeeds, -1 otherwise
You should loop on your content line by line, as follows:
for line in myFile:
if line.find(playerName):
print(line)
A safer way to read the file and find data, so that you will not have OutOfMemory issues when storing the whole file in memory.
playerName = input("Enter a player name to view their scores: ")
with open("Scores.txt", 'r') as f:
for row in f:
if playerName in row:
print row
This way you will be using with that will close the file by itself either when the program ends or Garbage Collection kicks in. This way python will read the file line by line and store only 1 line in memory. So you can use huge files and do not worry about memory issues.
Hope it helps :)
Working with str methods will take more acrobatics. Try the following,
import re
p = re.compile(r"\b{}\b".format(playername)) # keep it ready
# inside option B
for line in myfile: # no need to `.read()` it
match = p.search(line)
if match:
print(line)
break # if there is only one record for playername
See if it works for you.
similar thing here:
Reading specific lines only (Python)
fp = open("file")
for i, line in enumerate(fp):
if line == playername:
print line
fp.close()
I also notice you don't close your file for each decision, should make that happen.
Few python idioms and small optimization
Here are many answer, my sample brings in few python idioms and optimize it a bit:
fname = "Scores.txt"
player_name = "Quido"
with open(fname) as f:
for line in f:
if player_name in line:
print line
break
print "Going on doing following tasks."
The with block will close the open file on exiting the inner block. No need to f.close(), safe
in case of problems to read the file.
for line in f: shows, that iterating over file open in text mode we get one line per iteration.
break after we print the line with the player will effectively stop iterating over lines assuming,
there is only one such line or that we are happy with the very first one. If this is not the case,
removing the break allows printing all lines containing the player name.
As lines returned from text file iterator contain new line, you may prefer to get rid of them. Use
print line.strip() in such case what will remove all blank characters from start and end of the line.
Final print is proving, the program continues after it processes all the lines.
It may happen, that you get no output for name, which appears to be present in the file. In such a
case, you might need to clarify letter case. For example, if your text file contains all the names
in exact casing, you have to enter the name properly.
Other option is to lower-case the player_name and compare it against lower cased line:
fname = "Scores.txt"
player_name = "Quido"
normalized_player_name = player_name.lower()
with open(fname) as f:
for line in f:
if normalized_player_name in line.lower():
print line.strip()
break # comment out to print all lines with the player
print "Going on doing following tasks."
Note, that we normalize the player_name outside from the loop to be a bit faster. Lower-casing inside the
loop would work, but would do the same task repeatedly.
The line is printed using exact letter cases as in the file.
I'm writing a mini diceware program designed to take inputs from the users with real dice, look up the values, and print out their diceware passphrase.
The code I have at the moment works fine and pulls the number and words from a wordlist by searching for the 5-digit diceware identifier (e.g. 34465 jilt).
But, I'm hoping to make the pass phrase print as one line without the number association. e.g. as
"jilt load re open snap" instead of
34465 jilt
load
etc.
At the moment this is that code I'm using:
p_length = int(raw_input("How many dicewords?"))
roll_list = []
for i in range(p_length):
seq1 = (raw_input("roll 1:"), raw_input("roll 2:"),
raw_input("roll 3:"), raw_input("roll 4:"),
raw_input("roll 5:"))
str1 = "".join(seq1)
roll_list.append(str1)
print roll_list
with open("name_list.txt") as f:
for line in f:
for x in roll_list:
if x in line:
print line
Any suggestions on how to change the last few lines there to do what I'm hoping?
Thanks for the split() advice. Here is my solution:
passphrases = []
with open("name_list.txt") as f:
for line in f:
for x in roll_list:
if x in line:
var1 = line.split(" ")
var2 = var1.pop( )
passphrases.append(var2.rstrip('\n'))
print " ".join(passphrases)
You can use any here.Updated for just fixing.
for line in f:
if any(i for i in roll_list if i in line.strip()):
print line.strip().split(" ")[-1]
>>>hold romeo
You can use split to break up a line and extract just the word w/o the number.
import re
print "List of names:"
f=open('names.txt','r') #look below
lines = f.readlines()
for line in lines:
info = line.split('|')
names = info[0]
print names
name = raw_input("Enter the name of the person you want to delete: ")
f.close()
f = open('names.txt','w')
for line in lines:
if not re.match(name,line):
f.write(line)
break
print "That person doesn't exist!"
names.txt :
John|22|Nice
Johnny|55|Better than John
Peter|25|The worst
So, when you run the program, list of names is printed and then you have to enter the name of the person whose line you want to delete.
The problem is, if I enter John, it deletes the first and the second line, but I want only the first line to be deleted. My guess is that I'm not doing re.match() right. I tried re.match(name,names) but that doesn't work either.
So, the string you enter into name should be compared to the strings in names , and if there's an exact match, it should delete the line that has name as the first element.
I found a lot of similar problems but my function contains everything combined and I can't figure it out.
re.match matches the string at the beginning of the string. You may add word delimeter to your expression
name + r'\b'
but in your case, re is an overkill, simple comparison will do
name == line.partition('|')[0]
BTW, if you need to split only once at the beginning - or end - partition and rpartition functions are better options
EDIT
Timing:
>>> timeit('line.startswith(name+"|")', 'line="John|22|Nice";name="John"')
0.33100164101452345
>>> timeit('line.partition("|")[0] == name', 'line="John|22|Nice";name="John"')
0.2520693876228961
>>> timeit('re.match(name+r"\b", line)', 'import re; line="John|22|Nice";name="John"')
1.8754496594662555
>>> timeit('line.split("|")[0] == name', 'line="John|22|Nice";name="Jonny"')
0.511219799415926
Especially for Padraick
>>> timeit('line.partition("|")[0] == name', 'line="John|22|Nice";name="John"')
0.27333073995099083
>>> timeit('line.split("|", 1)[0] == name', 'line="John|22|Nice";name="John"')
0.5120651608158937
Frankly - I am surprised myself
with open("in.txt") as f:
lines = f.readlines()
name = raw_input("Enter the name of the person you want to delete: ").lower() + "|"
ln = len(name)
for ind, line in enumerate(lines):
if name == line[:ln].lower():
lines[ind:ind+1] = []
break
with open("in.txt","w") as out:
out.writelines(lines)
If you want to remove all John's etc.. don't break just keep looping and writing, as it stands we erase the first "John" we find. The fastest way is to just index.