python - if conditions in string is true - python

python beginner here. My file contains lines that consists of conditions that are formatted just like a python if statement (without the if in the beginning and colon in the end). Example:
temperature < 40 and weekday == "Thursday" and (country != "Norway" or country != "USA")
(temperature != 30 or temperature != 35) and weekday == "Friday" and country == "Canada"
I want to write code that reads the lines as if they were if statements and prints True or False depending on if the conditions were met. I am thinking something along the lines of:
temperature = 35
country = "Canada"
weekday = "Friday"
file = open('output.txt', r)
lines = file.readlines()
for line in lines:
if line:
# if conditions in string are met, print true
print(True)
else:
# else print False
print(False)
which should when run with above file lines should output
False
True
EDIT:
Would it be possible to reliably and consistently parse the file lines and process it, like how I'm assuming a python compiler would read an actual if statement?

Alright so you've got a few basic issues, mostly forgetting to use "" for strings such as in country = Canada and weekday = Friday. Other than that, you can use the eval() method, however, it is considered bad practice and you should try to avoid it.
temperature = 35
country = "Canada"
weekday = "Friday"
file = open('output.txt', "r")
lines = file.readlines()
for line in lines:
if eval(line):
# if conditions in string are met, print true
print(True)
else:
# else print False
print(False)
Note: Forgot to mention, you need "" for the read specifier in open().

There are two concepts, selection (if statements), and conditions / boolean logic <, or, and, etc. You are trying to use the 2nd. You are correct you don't need the 1st.
When we program we don't write big programs that don't work, the fix them. We start with small programs that work, and then make them bigger. So let me start with a simple example.
temperature < 40
How do we print True if this is true, and False if it is false? The answer may surprise you.
print(temperature < 40)

Related

Construct the next strings by using the string time format function strftime

Start by setting t to be the local time 1, 500, 000, 000 seconds from the start of January 1, 1970 UTC:
import time
t = time.localtime(1500000000)
Construct the next strings by using the string time format function strftime(): (a) 'Thursday, July 13 2017'
(b) '09:40 PM Central Daylight Time on 07/13/2017'
(c) 'I will meet you on Thu July 13 at 09:40 PM.'
A couple things, Stack Overflow is not the place for code reviews, for that: try this.
Regardless, you have indentation problems, Python is based off of indents, you need to have the code in your function indented one ahead of your def, like so:
def filesStringSearch():
infile = open('example.txt')
a = input('Search for a word: ')
result = infile.read().find(a)
#result = a.find:
#for a in infile:
if a.find:
print("True")
elif a < 3:
print("-1")
else:
print("False")
return
Second, you're not taking an input with the function, and hard-coding the file to open; this is a simple fix however,
def filesStringSearch(filename):
infile = open(filename)
Third, you're not going to accomplish your goal with your if statements, if the length of the input is less than 3, you shouldn't even try to search for anything, so you need to reorder and change your boolean expressions a bit; to this:
if len(a) < 3:
print("-1")
elif a.find:
print("True")
else:
print("False")
Finally, a.find will not work, rather you can check to see the value of result, so you can replace elif: a.find with:
elif result != -1:
print("True")
Since result will be -1 if it cannot find anything.
Also, the return is useless at the end.
According to your questions the right implementation is:
def filesStringSearch(filename, pattern):
with open(filename, 'r') as f:
text = f.read()
if len(pattern) >= 3:
return text.find(pattern) > -1 or False
else:
return -1
filename = 'example.txt'
pattern_to_find = input('Search for a word: ')
out = filesStringSearch(filename, pattern_to_find)
print(out)
If you are asked to write a function that accepts two arguments, then your function must accept two arguments as here:
def filesStringSearch(filename, pattern):
Then you must read the file, I did it using with statement. with statement will close our file for us, so you don't have to do it manually (and yes, you forgot to close an opened file, it is not a big problem for now, but avoid such things in big projects). You can read more about with statement there: Reading and writing files
What about find method. It is a string method, that will return index of found substring in your string, for instance my_string.find('h') is going to return the index of first substring (which is 'h') in my_string string. If find method can't find your substring it will return -1, that's why we do this:
return text.find(pattern) > -1 or False
As if we will find our pattern in text, then the index certainly is going to be greater that -1. Otherwise we return False or -1 if pattern string's length is less than 3, according to your question
And at the end we take input from user and pass that input to our function with the name of file example.txt. We store the return value of our function in out variable and then print it

Double if conditional in the line.startswith strategy

I have a data.dat file with this format:
REAL PART
FREQ 1.6 5.4 2.1 13.15 13.15 17.71
FREQ 51.64 51.64 82.11 133.15 133.15 167.71
.
.
.
IMAGINARY PART
FREQ 51.64 51.64 82.12 132.15 129.15 161.71
FREQ 5.64 51.64 83.09 131.15 120.15 160.7
.
.
.
REAL PART
FREQ 1.6 5.4 2.1 13.15 15.15 17.71
FREQ 51.64 57.64 82.11 183.15 133.15 167.71
.
.
.
IMAGINARY PART
FREQ 53.64 53.64 81.12 132.15 129.15 161.71
FREQ 5.64 55.64 83.09 131.15 120.15 160.7
All over the document REAL and IMAGINARY blocks are reported
Within the REAL PART block,
I would like to split each line that starts with FREQ.
I have managed to:
1) split lines and extract the value of FREQ and
2) append this result to a list of lists, and
3) create a final list, All_frequencies:
FREQ = []
fname ='data.dat'
f = open(fname, 'r')
for line in f:
if line.startswith(' FREQ'):
FREQS = line.split()
FREQ.append(FREQS)
print 'Final FREQ = ', FREQ
All_frequencies = list(itertools.chain.from_iterable(FREQ))
print 'All_frequencies = ', All_frequencies
The problem with this code is that it also extracts the IMAGINARY PART values of FREQ. Only the REAL PART values of FREQ would have to be extracted.
I have tried to make something like:
if line.startswith('REAL PART'):
if line.startswith('IMAGINARY PART'):
code...
or:
if line.startswith(' REAL') and line.startswith(' FREQ'):
code...
But this does not work. I would appreciate if you could help me
It appears based on the sample data in the question that lines starting with 'REAL' or 'IMAGINARY' don't have any data on them, they just mark the beginning of a block. If that's the case (and you don't go changing the question again), you just need to keep track of which block you're in. You can also use yield instead of building up an ever-larger list of frequencies, as long as this code is in a function.
def read_real_parts(fname):
f = open(fname, 'r')
real_part = False
for line in f:
if line.startswith(' REAL'):
real_part = True
elif line.startswith(' IMAGINARY'):
real_part = False
elif line.startswith(' FREQ') and real_part:
FREQS = line.split()
yield FREQS
FREQ = read_real_parts('data.dat') #this gives you a generator
All_frequencies = list(itertools.chain.from_iterable(FREQ)) #then convert to list
Think of this as a state machine having two states. In one state, when the program has read a line with REAL at the beginning it goes into the REAL state and aggregates values. When it reads a line with IMAGINARY it goes into the alternate state and ignores values.
REAL, IMAGINARY = 1,2
FREQ = []
fname = 'data.dat'
f = open(fname)
state = None
for line in f:
line = line.strip()
if not line: continue
if line.startswith('REAL'):
state = REAL
continue
elif line.startswith('IMAGINARY'):
state = IMAGINARY
continue
else:
pass
if state == IMAGINARY:
continue
freqs = line.split()[1:]
FREQ.extend(freqs)
I assume that you want only the numeric values; hence the [:1] at the end of the assignment to freqs near the end of the script.
Using your data file, without the ellipsis lines, produces the following result in FREQ:
['1.6', '5.4', '2.1', '13.15', '13.15', '17.71', '51.64', '51.64', '82.11', '133.15', '133.15', '167.71', '1.6', '5.4', '2.1', '13.15', '15.15', '17.71', '51.64', '57.64', '82.11', '183.15', '133.15', '167.71']
You would need to keep track of which part you are looking at, so you can use a flag to do this:
section = None #will change to either "real" or "imag"
for line in f:
if line.startswith("IMAGINARY PART"):
section = "imag"
elif line.startswith('REAL PART'):
section = "real"
else:
freqs = line.split()
if section == "real":
FREQ.append(freqs)
#elif section == "imag":
# IMAG_FREQ.append(freqs)
by the way, instead of appending to FREQ then needing to use itertools.chain.from_iterable you might consider just extending FREQ instead.
we start with a flag set to False. if we find a line that contains "REAL", we set it to True to start copying the data below the REAL part, until we find a line that contains IMAGINARY, which sets the flag to False and goes to the next line until another "REAL" is found (and hence the flag turns back to True)
using the flag concept in a simple way:
with open('this.txt', 'r') as content:
my_lines = content.readlines()
f=open('another.txt', 'w')
my_real_flag = False
for line in my_lines:
if "REAL" in line:
my_real_flag = True
elif "IMAGINARY" in line:
my_real_flag = False
if my_real_flag:
#do code here because we found real frequencies
f.write(line)
else:
continue #because my_real_flag isn't true, so we must have found a
f.close()
this.txt looks like this:
REAL
1
2
3
IMAGINARY
4
5
6
REAL
1
2
3
IMAGINARY
4
5
6
another.txt ends up looking like this:
REAL
1
2
3
REAL
1
2
3
Original answer that only works when there is one REAL section
If the file is "small" enough to be read as an entire string and there is only one instance of "IMAGINARY PART", you can do this:
file_str = file_str.split("IMAGINARY PART")[0]
which would get you everything above the "IMAGINARY PART" line.
You can then apply the rest of your code to this file_str string that contains only the real part
to elaborate more, file_str is a str which is obtained by the following:
with open('data.dat', 'r') as my_data:
file_str = my_data.read()
the "with" block is referenced all over stack exchange, so there may be a better explanation for it than mine. I intuitively think about it as "open a file named 'data.dat' with the ability to only read it and name it as the variable my_data. once its opened, read the entirety of the file into a str, file_str, using my_data.read(), then close 'data.dat' "
now you have a str, and you can apply all the applicable str functions to it.
if "IMAGINARY PART" happens frequently throughout the file or the file is too big, Tadgh's suggestion of a flag a break works well.
for line in f:
if "IMAGINARY PART" not in line:
#do stuff
else:
f.close()
break

Returning every instance of whatever's between two strings in a file [Python 3]

What I'm trying to do is open a file, then find every instance of '[\x06I"' and '\x06;', then return whatever is between the two.
Since this is not a standard text file (it's map data from RPG maker) readline() will not work for my purposes, as the file is not at all formatted in such a way that the data I want is always neatly within one line by itself.
What I'm doing right now is loading the file into a list with read(), then simply deleting characters from the very beginning until I hit the string '[\x06I'. Then I scan ahead to find '\x06;', store what's between them as a string, append said string to a list, then resume at the character after the semicolon I found.
It works, and I ended up with pretty much exactly what I wanted, but I feel like that's the worst possible way to go about it. Is there a more efficient way?
My relevant code:
while eofget == 0:
savor = 0
while savor == 0 or eofget == 0:
if line[0:4] == '[\x06I"':
x = 4
spork = 0
while spork == 0:
x += 1
if line[x] == '\x06':
if line[x+1] == ';':
spork = x
savor = line[5:spork] + "\n"
line = line[x+1:]
linefinal[lineinc] = savor
lineinc += 1
elif line[x:x+7] == '#widthi':
print("eof reached")
spork = 1
eofget = 1
savor = 0
elif line[x:x+7] == '#widthi':
print("finished map " + mapname)
eofget = 1
savor = 0
break
else:
line = line[1:]
You can just ignore the variable names. I just name things the first thing that comes to mind when I'm doing one-offs like this. And yes, I am aware a few things in there don't make any sense, but I'm saving cleanup for when I finalize the code.
When eofget gets flipped on this subroutine terminates and the next map is loaded. Then it repeats. The '#widthi' check is basically there to save time, since it's present in every map and indicates the beginning of the map data, AKA data I don't care about.
I feel this is a natural case to use regular expressions. Using the findall method:
>>> s = 'testing[\x06I"text in between 1\x06;filler text[\x06I"text in between 2\x06;more filler[\x06I"text in between \n with some line breaks \n included in the text\x06;ending'
>>> import re
>>> p = re.compile('\[\x06I"(.+?)\x06;', re.DOTALL)
>>> print(p.findall(s))
['text in between 1', 'text in between 2', 'text in between \n with some line breaks \n included in the text']
The regex string '\[\x06I"(.+?)\x06;'can be interpreted as follows:
Match as little as possible (denoted by ?) of an undetermined number of unspecified characters (denoted by .+) surrounded by '[\x06I"' and '\x06;', and only return the enclosed text (denoted by the parentheses around .+?)
Adding re.DOTALL in the compile makes the .? match line breaks as well, allowing multi-line text to be captured.
I would use split():
fulltext = 'adsfasgaseg[\x06I"thisiswhatyouneed\x06;sdfaesgaegegaadsf[\x06I"this is the second what you need \x06;asdfeagaeef'
parts = fulltext.split('[\x06I"') # split by first label
results = []
for part in parts:
if '\x06;' in part: # if second label exists in part
results.append(part.split('\x06;')[0]) # get the part until the second label
print results

Date conversion from numbers to words in Python

I wrote a program in python(I'm a beginner still) that converts a date from numbers to words using dictionaries. The program is like this:
dictionary_1 = { 1:'first', 2:'second'...}
dictionary_2 = { 1:'January', 2:'February',...}
and three other more for tens, hundreds, thousands;
2 functions, one for years <1000, the other for years >1000;
an algorithm that verifies if it's a valid date.
In main I have:
a_random_date = raw_input("Enter a date: ")
(I've chosen raw_input for special chars. between numbers such as: 21/11/2014 or 21-11-2014 or 21.11.2014, only these three) and after verifying if it's a valid date I do not know nor did I find how to call upon the dictionaries to convert the date into words, when I run the program I want at the output for example if I typed 1/1/2015: first/January/two thousand fifteen.
And I would like to apply the program to a text document to seek the dates and convert them from numbers to words if it is possible.
Thank you!
You can split that date in list and then check if there is that date in dictionary like this:
import re
dictionary_1 = { 1:'first', 2:'second'}
dictionary_2 = { 1:'January', 2:'February'}
dictionary_3 = { 1996:'asd', 1995:'asd1'}
input1 = raw_input("Enter date:")
lista = re.split(r'[.\/-]', input1)
print "lista: ", lista
day = lista[0]
month = lista[1]
year = lista[2]
everything_ok = False
if dictionary_1.get(int(day)) != None:
day_print = dictionary_1.get(int(day))
everything_ok = True
else:
print "There is no such day"
if dictionary_2.get(int(month)) != None:
month_print = dictionary_2.get(int(month))
everything_ok = True
else:
print "There is no such month"
everything_ok = False
if dictionary_3.get(int(year)) != None:
year_print = dictionary_3.get(int(year))
everything_ok = True
else:
print "There is no such year"
everything_ok = False
if everything_ok == True:
print "Date: ", day_print, "/", month_print, "/", year_print #or whatever format
else:
pass
This is the output:
Enter date:1/2/1996
Date: first / February / asd
I hope this helps you.
Eventually you will need the re module. Learn to write a regular expression that can search strings of a particular format. Here's some code example:
with open("mydocument.txt") as f:
contents = f.read()
fi = re.finditer(r"\d{1,2}-\d{1,2}-\d{4}", contents)
This will find all strings that are made up of 1 or 2 digits followed by a hyphen, followed by another 1 or 2 digits followed by a hyphen, followed by 4 digits. Then, you feed each string into datetime.strptime; it will parse your "date" string and decide if it is valid according to your specified format.
Have fun!

str.startswith() not working as I intended

I'm trying to test for a /t or a space character and I can't understand why this bit of code won't work. What I am doing is reading in a file, counting the loc for the file, and then recording the names of each function present within the file along with their individual lines of code. The bit of code below is where I attempt to count the loc for the functions.
import re
...
else:
loc += 1
for line in infile:
line_t = line.lstrip()
if len(line_t) > 0 \
and not line_t.startswith('#') \
and not line_t.startswith('"""'):
if not line.startswith('\s'):
print ('line = ' + repr(line))
loc += 1
return (loc, name)
else:
loc += 1
elif line_t.startswith('"""'):
while True:
if line_t.rstrip().endswith('"""'):
break
line_t = infile.readline().rstrip()
return(loc,name)
Output:
Enter the file name: test.txt
line = '\tloc = 0\n'
There were 19 lines of code in "test.txt"
Function names:
count_loc -- 2 lines of code
As you can see, my test print for the line shows a /t, but the if statement explicitly says (or so I thought) that it should only execute with no whitespace characters present.
Here is my full test file I have been using:
def count_loc(infile):
""" Receives a file and then returns the amount
of actual lines of code by not counting commented
or blank lines """
loc = 0
for line in infile:
line = line.strip()
if len(line) > 0 \
and not line.startswith('//') \
and not line.startswith('/*'):
loc += 1
func_loc, func_name = checkForFunction(line);
elif line.startswith('/*'):
while True:
if line.endswith('*/'):
break
line = infile.readline().rstrip()
return loc
if __name__ == "__main__":
print ("Hi")
Function LOC = 15
File LOC = 19
\s is only whitespace to the re package when doing pattern matching.
For startswith, an ordinary method of ordinary strings, \s is nothing special. Not a pattern, just characters.
Your question has already been answered and this is slightly off-topic, but...
If you want to parse code, it is often easier and less error-prone to use a parser. If your code is Python code, Python comes with a couple of parsers (tokenize, ast, parser). For other languages, you can find a lot of parsers on the internet. ANTRL is a well-known one with Python bindings.
As an example, the following couple of lines of code print all lines of a Python module that are not comments and not doc-strings:
import tokenize
ignored_tokens = [tokenize.NEWLINE,tokenize.COMMENT,tokenize.N_TOKENS
,tokenize.STRING,tokenize.ENDMARKER,tokenize.INDENT
,tokenize.DEDENT,tokenize.NL]
with open('test.py', 'r') as f:
g = tokenize.generate_tokens(f.readline)
line_num = 0
for a_token in g:
if a_token[2][0] != line_num and a_token[0] not in ignored_tokens:
line_num = a_token[2][0]
print(a_token)
As a_token above is already parsed, you can easily check for function definition, too. You can also keep track where the function ends by looking at the current column start a_token[2][1]. If you want to do more complex things, you should use ast.
You string literals aren't what you think they are.
You can specify a space or TAB like so:
space = ' '
tab = '\t'

Categories