Evaluation of IF statement in Python - python

Please help me try to understand the evaluation of this script. It must be something simple I'm not understanding. I want to scan a text file and output lines with specific string value.
So for example my txt file will contain simple stuff:
beep
boop
bop
Hey
beep
boop
bop
and the script is looking for the line with "Hey" and trying to output that line
file_path = "C:\\downloads\\test.txt"
i = 0
file_in = open(file_path,"r+") # read & write
for lines in file_in.readlines():
i+=1
#if lines.rfind("this entity will be skipped..."):
if lines.find("Hey"):
print(i, lines)
file_in.close()
For some reason it outputs every line except the one it found a match on. How is this possible?

It's probably more straightforward to do if "Hey" in lines: instead of if lines.find("Hey"):. If you really want to use find(), you could do this: if lines.find("Hey") != -1:

While Daniel's answer is, of course, correct and should be accepted, I want to fuel my OCD and offer some improvements:
# use context managers to automatically release file handler
with open(file_path) as file_in:
# file objects are iterable, will return lines
# reading entire file in memory can crash if file is too big
# enumerate() is a more readable alternative to manual counters
for i, line in enumerate(file_in): # 'line' should be singular
if "Hey" in line: # same as Daniel
print(i, line)

.find(sub) returns an integer - the first index of sub if sub is found, and -1 if it is not.
When "Hey" is present, it is at the first index (0), so that is what .find() returns. Otherwise, "Hey" is not found, so .find() returns -1.
Since python treats all integers as True except 0, then the conditional evaluates to True when 0 is returned, i.e. when "Hey" is found.
Change your use of .find() to something which fulfills your if statement the way you want.

Related

Replace words in list that later will be used in variable

I have a file which currently stores a string eeb39d3e-dd4f-11e8-acf7-a6389e8e7978
which I am trying to pass into as a variable to my subprocess command.
My current code looks like this
with open(logfilnavn, 'r') as t:
test = t.readlines()
print(test)
But this prints ['eeb39d3e-dd4f-11e8-acf7-a6389e8e7978\n'] and I don't want the part with ['\n'] to be passed into my command, so i'm trying to remove them by using replace.
with open(logfilnavn, 'r') as t:
test = t.readlines()
removestrings = test.replace('[', '').replace('[', '').replace('\\', '').replace("'", '').replace('n', '')
print(removestrings)
I get an exception value saying this so how can I replace these with nothing and store them as a string for my subprocess command?
'list' object has no attribute 'replace'
so how can I replace these with nothing and store them as a string for my subprocess command?
readline() returns a list. Try print(test[0].strip())
You can read the whole file and split lines using str.splitlines:
test = t.read().splitlines()
Your test variable is a list, because readlines() returns a list of all lines read.
Since you said the file only contains this one line, you probably wish to perform the replace on only the first line that you read:
removestrings = test[0].replace('[', '').replace('[', '').replace('\\', '').replace("'", '').replace('n', '')
Where you went wrong...
file.readlines() in python returns an array (collection or grouping of the same variable type) of the lines in the file -- arrays in python are called lists. you, here are treating the list as a string. you must first target the string inside it, then apply that string-only function.
In this case however, this would not work as you are trying to change the way the python interpretter has displayed it for one to understand.
Further information...
In code it would not be a string - we just can't easily understand the stack, heap and memory addresses easily. The example below would work for any number of lines (but it will only print the first element) you will need to change that and
this may be useful...
you could perhaps make the variables globally available (so that other parts of the program can read them
more useless stuff
before they go out of scope - the word used to mean the points at which the interpreter (what runs the program) believes the variable is useful - so that it can remove it from memory, or in much larger programs only worry about the locality of variables e.g. when using for loops i is used a lot without scope there would need to be a different name for each variable in the whole project. scopes however get specialised (meaning that if a scope contains the re-declaration of a variable this would fail as it is already seen as being one. an easy way to understand this might be to think of them being branches and the connections between the tips of branches. they don't touch along with their variables.
solution?
e.g:
with open(logfilenavn, 'r') as file:
lines = file.readlines() # creates a list
# an in-line for loop that goes through each item and takes off the last character: \n - the newline character
#this will work with any number of lines
strippedLines = [line[:-1] for line in lines]
#or
strippedLines = [line.replace('\n', '') for line in lines]
#you can now print the string stored within the list
print(strippedLines[0]) # this prints the first element in the list
I hope this helped!
You get the error because readlines returns a list object. Since you mentioned in the comment that there is just one line in the file, its better to use readline() instead,
line = "" # so you can use it as a variable outside `with` scope,
with open("logfilnavn", 'r') as t:
line = t.readline()
print(line)
# output,
eeb39d3e-dd4f-11e8-acf7-a6389e8e7978
readlines will return a list of lines, and you can't use replace with a list.
If you really want to use readlines, you should know that it doesn't remove the newline character from the end, you'll have to do it yourself.
lines = [line.rstrip('\n') for line in t.readlines()]
But still, after removing the newline character yourself from the end of each line, you'll have a list of lines. And from the question, it looks like, you only have one line, you can just access first line lines[0].
Or you can just leave out readlines, and just use read, it'll read all of the contents from the file. And then just do rstrip.
contents = t.read().rstrip('\n')

Python If == true statement only working on last line of readline

My function only says that the last word in a file of words is an anagram (the first helper function). But every word in the file is an anagram of the word I tested and returns true independently with the helper function outside of the main function. I am not sure if it has something to do with /n being a part of the string, and then it accounting for that, but I tried putting in an if statement saying to delete it if it was in there and that did not work either. I also did test to make sure it is running through each word in the .txt file and it is.
def is_anagram(string1, string2):
"""Returns True if the two strings are anagrams of eachother.
str, str -> bool"""
if sorted(string1)==sorted(string2):
return True
else:
return False
def find_anagrams(word):
final = []
content = open("small_list.txt")
content.close
while True:
line = content.readline()
print(line)
if is_anagram(word, line) == True:
print("bruh")
final.append(line)
elif line == '':
break
return final
This is expected, based on the method you use to read a line (file.readline). From the documentation:
f.readline() reads a single line from the file; a newline character
(\n) is left at the end of the string, and is only omitted on the last
line of the file if the file doesn’t end in a newline.
Your line has a trailing newline, but word certainly does not. So, in the end, all you'd need to change is:
line = content.readline().rstrip()
Well, that's all you'd need to change to get it working. Additionally, I'd also recommend using the with...as context manager to handle file I/O. It's good practice, and you'll thank yourself for it.
with open("small_list.txt") as f:
for line in f:
if is_anagram(word, line.rstrip()):
... # do something here
It's better to use a for loop to iterate over the lines of a file (rather than a while, it's cleaner). Also, there's no need to explicitly call f.close() when you use a context manager (you're not currently doing it, you're only referencing the method without actually calling it).
Incorporating #Christian Dean's suggestion in this answer, you can simplify your anagram function as well - call sorted and return the result in a single line:
def is_anagram(a, b):
return sorted(a) == sorted(b)

how to print missing line in python?

I am searching a particular line in a file.
If my required line is not present i want to print that line is missing in the file.
For example my file contains below lines:
list 0
list 7
list 2
list 5
Here is the I have written so far :
fo=open(filename,"r")
for i in range(0,6):
str="list"+str(i)
for line in fo.readlines():
if not str in line:
print "%s%s" %(str,"is missing in file"
please anyone help me
The first problem is that list+str(i) isn't going to work, unless you happen to have defined list = 'list ' somewhere earlier.
The second problem is that by naming your variable str, you're hiding the function str, which means you can't call that function the next time through the loop.
The third problem is that you only open the file once, but you call readlines() on it 7 times. After the first time, there are no more lines to read, so you'll get an empty list back. Just call it once, outside the loop, and store the value: lines = fo.readlines(). Or, alternatively, reopen the file each time through the loop, instead of just once.
The third problem is that you're going to print the output once for every line that doesn't, instead of just one if any line doesn't match. This one is the only part that's tricky, so I'll come back to it.
The fourth problem is that your print statement is missing a ).
Finally, you've tagged your question with both python-2.7 and python-3.x. I'll assume you weren't just trying to throw on every tag in the world in hopes that would get more viewers, and actually want your code to run under both 2.7 and 3.3. In that case, you can't use print as a statement; you have to use it as a function.
So, how do you say "if the string is not in any of the lines"? The easy way is with the any function:
if not any(s in line for line in lines):
If you can't understand that, you can get the same effect by writing out the loop explicitly, something like this:
found = False
for line in lines:
if s in line:
found = True
break
if not found:
There are a lot of other problems that you should fix (e.g., close the file—ideally by using a with statement; avoid readlines when possible; etc.), but no more that you need to fix. So, here's a minimally-edited working version:
fo=open(filename,"r")
lines = fo.readlines()
for i in range(0,6):
s='list '+str(i)
if not any(s in line for line in lines):
print("%s%s" %(s,"is missing in file"))
You should never name a variable str as str is a builtin type in Python. Also, you were attempting to concatenate list, a function and a type, and a string. Instead you want to concatenate the string 'list ' with the string representation of the numbers. You don't need to call readlines() where you did. Instead, read the file into a list early and iterate over that list.
fo=open(filename,"r").readlines()
for i in range(0,6):
s = 'list ' + str(i)
foundline = False
for line in fo:
if s in line:
foundline = True
break
if not foundline:
print "%s%s" % (s,"is missing in file")
with open(filename,'r') as infile:
inlines=infile.readlines()
for term in xrange(0,10):
line='list %d\n' % term
if line not in inlines:
print line,'is not in the file'
//nb, this matches the entire search string to the input line. I assume you mean this rather than to look for the search term inside the input line, becuase searching for 'line 1' inside the line would match against 'line 1', 'line 10', 'line 1000' etc..

Use readlines() with indices or parse lines on the fly?

I'm making a simple test function that asserts that the output from an interpreter I'm developing is correct, by reading from a file the expression to evaluate and the expected result, much like python's doctest. This is for scheme, so an example of an input file would be
> 42
42
> (+ 1 2 3)
6
My first attempt for a function that can parse such a file looks like the following, and it seems to work as expected:
def run_test(filename):
interp = Interpreter()
response_next = False
num_tests = 0
with open(filename) as f:
for line in f:
if response_next:
assert response == line.rstrip('\n')
response_next = False
elif line.startswith('> '):
num_tests += 1
response = interp.eval(line[2:])
response = str(response) if response else ''
response_next = True
print "{:20} Ran {} tests successfully".format(os.path.basename(filename),
num_tests)
I wanted to improve it slightly by removing the response_next flag, as I am not a fan of such flags, and instead read in the next line within the elif block with next(f). I had a small unrelated question regarding that which I asked about in IRC at freenode. I got the help I wanted but I was also given the suggestion to use f.readlines() instead, and then use indexing on the resulting list. (I was also told that I could use groupby() in itertools for the pairwise lines, but I'll investigate that approach later.)
Now to the question, I was very curious why that approach would be better, but my Internet connection was a flaky one on a train and I was unable to ask, so I'll ask it here instead. Why would it be better to read everything with readlines() instead of parsing every line as they are read on the fly?
I'm really wondering as my feeling is the opposite, I think it seems cleaner to parse the lines one at a time so that everything is finished in one go. I usually avoid using indices in arrays in Python and prefer to work with iterators and generators. Maybe it is impossible to answer and guess what the person was thinking in case it was a subjective opinion, but if there is some general recommendation I'd be happy to hear about it.
It's certainly more Pythonic to process input iteratively rather than reading the whole input at once; for example, this will work if the input is a console.
An argument in favour of reading a whole array and indexing is that using next(f) could be unclear when combined with a for loop; the options there would be either to replace the for loop with a while True or to fully document that you are calling next on f within the loop:
try:
while True:
test = next(f)
response = next(f)
except StopIteration:
pass
As Jonas suggests you could accomplish this (if you're sure that the input will always consist of lines test/response/test/response etc.) by zipping the input with itself:
for test, response in zip(f, f): # Python 3
for test, response in itertools.izip(f, f): # Python 2
Reading everything into an array gives you the equivalent of random access: You use an array index to move down the array, and at any time you can check what's next and back up if necessary.
If you can carry out your task without backing up, you don't need the random access and it would be cleaner to do without it. In your examples, it seems that your syntax is always a single-line (?) expression followed by the expected response. So, I'd have written a top-level loop that iterates once per expression-value pair, reading lines as necessary.
If you want to support multi-line expressions and results, you can write separate functions to read each one: One that reads a complete expression, one that reads a result (up to the next blank line). The important thing is they should be able consume as much input as they need, and leave the input pointer in a reasonable state for the next input.
from itertools import ifilter,imap
def run_test(filename):
interp = Interpreter()
num_tests, num_passed, last_result = 0, 0, None
with open(filename) as f:
# iterate over non-blank lines
for line in ifilter(None, imap(str.strip, f)):
if line.startswith('> '):
last_result = interp.eval(line[2:])
else:
num_tests += 1
try:
assert line == repr(last_test_result)
except AssertionError, e:
print e.message
else:
num_passed += 1
print("Ran {} tests, {} passed".format(num_tests, num_passed))
... this simply assumes that any result-line refers to the preceding test.
I would avoid .readlines() unless you get get some specific benefit from having the whole file available at once.
I also changed the comparison to look at the representation of the result, so it can distinguish between output types, ie
'6' + '2'
> '62'
60 + 2
> 62

AttributeError: 'str' object has no attribute 'readline'

Update: My current question is how can I get my code to read to the EOF starting from the beginning with each new search phrase.
This is an assignment I am doing and currently stuck on. Mind you this is a beginner's programming class using Python.
jargon = open("jargonFile.txt","r")
searchPhrase = raw_input("Enter the search phrase: ")
while searchPhrase != "":
result = jargon.readline().find(searchPhrase)
if result == -1:
print "Cannot find this term."
else:
print result
searchPhrase = raw_input("Enter the search phrase: ")
jargon.close()
The assignment is to take a user's searchPhrase and find it in a file (jargonFile.txt) and then have it print the result (which is the line it occured and the character occurence). I will be using a counter to find the line number of the occurence but I will implement this later. For now my question is the error I am getting. I cann't find a way for it to search the entire file.
Sample run:
Enter the search phrase: dog
16
Enter the search phrase: hack
Cannot find this term.
Enter the search phrase:
"dog" is found in the first line however it is also found in other lines of the jargonFile (multiple times as a string) but it is only showing the first occurence in the first line. The string hack is found numerous times in the jargonFile but my code is setup to only search the first line. How may I go about solving this problem?
If this is not clear enough I can post up the assignment if need be.
First you open the file and read it into a string with readline(). Later on you try to readline() from the string you obtained in the first step.
You need to take care what object (thing) you're handling: open() gave you a file "jargon", readline on jargon gave you the string "jargonFile".
So jargonFile.readline does not make sense anymore
Update as answer to comment:
Okay, now that the str error problem is solved think about the program structure:
big loop
enter a search term
open file
inner loop
read a line
print result if string found
close file
You'd need to change your program so it follows that descripiton
Update II:
SD, if you want to avoid reopening the file you'd still need two loops, but this time one loop reads the file into memory, when that's done the second loop asks for the search term. So you would structure it like
create empty list
open file
read loop:
read a line from the file
append the file to the list
close file
query loop:
ask the user for input
for each line in the array:
print result if string found
For extra points from your professor add some comments to your solution that mention both possible solutions and say why you choose the one you did. Hint: In this case it is a classic tradeoff between execution time (memory is fast) and memory usage (what if your jargon file contains 100 million entries ... ok, you'd use something more complicated than a flat file in that case, bu you can't load it in memory either.)
Oh and one more hint to the second solution: Python supports tuples ("a","b","c") and lists ["a","b","c"]. You want to use the latter one, because list can be modified (a tuple can't.)
myList = ["Hello", "SD"]
myList.append("How are you?")
foreach line in myList:
print line
==>
Hello
SD
How are you?
Okay that last example contains all the new stuff (define list, append to list, loop over list) for the second solution of your program. Have fun putting it all together.
Hmm, I don't know anything at all about Python, but it looks to me like you are not iterating through all the lines of the file for the search string entered.
Typically, you need to do something like this:
enter search string
open file
if file has data
start loop
get next line of file
search the line for your string and do something
Exit loop if line was end of file
So for your code:
jargon = open("jargonFile.txt","r")
searchPhrase = raw_input("Enter the search phrase: ")
while searchPhrase != "":
<<if file has data?>>
<<while>>
result = jargon.readline().find(searchPhrase)
if result == -1:
print "Cannot find this term."
else:
print result
<<result is not end of file>>
searchPhrase = raw_input("Enter the search phrase: ")
jargon.close()
Cool, did a little research on the page DNS provided and Python happens to have the "with" keyword. Example:
with open("hello.txt") as f:
for line in f:
print line
So another form of your code could be:
searchPhrase = raw_input("Enter the search phrase: ")
while searchPhrase != "":
with open("jargonFile.txt") as f:
for line in f:
result = line.find(searchPhrase)
if result == -1:
print "Cannot find this term."
else:
print result
searchPhrase = raw_input("Enter the search phrase: ")
Note that "with" automatically closes the file when you're done.
Your file is jargon, not jargonFile (a string). That's probably what's causing your error message. You'll also need a second loop to read each line of the file from the beginning until you find the word you're looking for. Your code currently stops searching if the word is not found in the current line of the file.
How about trying to write code that only gives the user one chance to enter a string? Input that string, search the file until you find it (or not) and output a result. After you get that working you can go back and add the code that allows multiple searches and ends on an empty string.
Update:
To avoid iterating the file multiple times, you could start your program by slurping the entire file into a list of strings, one line at a time. Look up the readlines method of file objects. You can then search that list for each user input instead of re-reading the file.
you shouldn't try to re-invent the wheel. just use the
re module functions.
your program could work better if you used:
result = jargon.read() .
instead of:
result = jargon.readline() .
then you could use the re.findall() function
and join the strings (with the indexes) you searched for with str.join()
this could get a little messy but if take some time to work it out, this could fix your problem.
the python documentation has this perfectly documented
Everytime you enter a search phrase, it looks for it on the next line, not the first one. You need to re-open the file for every search phrase, if you want it behave like you describe.
Take a look at the documentation for File objects:
http://docs.python.org/library/stdtypes.html#file-objects
You might be interested in the readlines method. For a simple case where your file is not enormous, you could use that to read all the lines into a list. Then, whenever you get a new search string, you can run through the whole list to see whether it's there.

Categories

Resources