Python - read from file skip lines starts with # - python

Try to read file and make a dictionary from lines, skippipng lines starts with # symbol
file example:
param1=val1
# here is comment
My function:
def readFromFile(name):
config = {}
with open(name, "r") as f:
for line in f.readlines():
li=line.lstrip()
if not li.startswith("#"):
config[line.split('=')[0]] = line.split('=')[1].strip()
return config
I get list index out of range error
But!
if i try to skip lines starts with, for example, symbol "h" - function works well...

Try with:
def readFromFile(name):
config = {}
with open(name, "r") as f:
for line in f.readlines():
li = line.lstrip()
if not li.startswith("#") and '=' in li:
key, value = line.split('=', 1)
config[key] = value.strip()
return config
You maybe have a blank line which breaks your split()

Your code works just fine, except for lines that neither start with a # nor contain a = character. Usually, those are empty lines.
Test for the = character before splitting:
def readFromFile(name):
config = {}
with open(name, "r") as f:
for line in f.readlines():
li=line.lstrip()
if not li.startswith("#") and '=' in li:
config[line.split('=')[0]] = line.split('=')[1].strip()
return config
You can simplify the code and make it a dict comprehension:
def readFromFile(name):
with open(name, "r") as f:
return {k: v
for line in f
for (k, v) in (line.strip().split('=', 1),)
if '=' in line.strip() and line[:1] != '#'}
You can loop over f (a file object) directly; no need to read all lines into memory using f.readlines() first. I used .split('=', 1) to only split on the equals sign once.

You can return a dictionary directly:
def readFromFile(name):
with open(name) as f:
return { line.split('=')[0]:line.split('=')[1].strip() for line in f \
if not line.startswith('#' and '=' in line }

Related

How can I remove the method arguments from a method declaration from a source code file and write it back?

I have a .txt file that contains pre-processed source code. It looks like this:
public static <V, E> E addEdgeWithVertices(Graph<V, E> g, V sourceVertex, V targetVertex)
g.addVertex(sourceVertex);
g.addVertex(targetVertex);
return g.addEdge(sourceVertex, targetVertex);
I want to get rid of the method arguments in the first line(method declaration) i.e. Graph<V, E> g, V sourceVertex, V targetVertex and write this back to my same file.
This is my code, it doesn't seem to work:
with open('source_code.txt', 'r') as f:
lines = f.readlines()
match_parameters = re.search("(public|protected|private|static) .*\((.*)\)", lines[0])
remove_parameters =
match_parameters.group(0).replace(match_parameters[2], "")
with open('source_code.txt', 'w') as f:
f.writelines(remove_parameters)
Actual Output(remaining lines are missing):
public static <V, E> E addEdgeWithVertices()
Expected Output:
public static <V, E> E addEdgeWithVertices()
g.addVertex(sourceVertex);
g.addVertex(targetVertex);
return g.addEdge(sourceVertex, targetVertex);
If you know that it will always be in the first line, you can do:
import re
with open('source_code.txt', 'r') as f:
lines = f.readlines()
match_parameters = re.search("(public|protected|private|static) .*\((.*)\)", lines[0])
remove_parameters = match_parameters.group(0).replace(match_parameters[2], "")
lines[0] = remove_parameters + "\n"
with open('source_code.txt', 'w') as f:
f.writelines("".join(lines))
You should be searching all the lines. And don't forget to add the original line whenever search returns None.
clean_code = []
with open('source_code.txt', 'r') as f:
lines = f.readlines()
for line in lines:
match_parameters = re.search("(public|protected|private|static) .*\((.*)\)", line)
if match_parameters is not None:
clean_code.append(match_parameters.group(0).replace(match_parameters[2], "") + "\n")
else:
clean_code.append(line)
with open('source_code.txt', 'w') as f:
f.writelines(clean_code)
However, use Calvin's answer if in fact the replacement has to be done only on the first line.

Python : Why do new lines keep appearing after every value amend?

I'm new to python and I'm trying various small things to see how they work:
items = dict()
with open(path) as f:
content = f.readlines()
for line in content:
splitStuff = line.split('!')
if splitStuff[0] in item:
items[splitStuff[0]] += ',' + Results[1]
else:
items[splitStuff[0]] = Results[1]
f.close()
with open(path2, 'a') as f:
for key, value in items.items():
f.write(key + '!' + value)
f.close()
It opens a file with this content:
3!Angel
3!Devil
4!Nasko
4!Pesho
4!Gosho
5!Kalin
6!Gancho
6!Boncho
6!Toncho
6!Moncho
And ends up writing a file with this content:
3!Angel
,Devil
4!Nasko
,Pesho
,Gosho
5!Kalin
6!Gancho
,Boncho
,Toncho
,Moncho
The part I don't understand is where are those new lines appearing from every time I edit a value?
EDIT: This is the desired output.
3!Angel,Devil
4!Nasko,Pesho,Gosho
5!Kalin
6!Gancho,Boncho,Toncho,Moncho
EDIT2: Never mind figured it out. Its because there are new lines in the original file and apparently reading file line by line catches them as well in python, unlike c# where they are ignored.
Lines you read with readlines() have a trailing newline.
for line in content:
line = line.rstrip()
splitStuff = line.split('!')
... etc ...
A solution could look like this:
path = "file1"
path2 = "file2"
items = dict()
with open(path) as f:
content = f.readlines()
for line in content:
splitStuff = line.split('!')
if splitStuff[0] in items:
items[splitStuff[0]] += ',' + splitStuff[1][:-1]
else:
items[splitStuff[0]] = splitStuff[1][:-1]
f.close()
with open(path2, 'a') as f:
for key, value in items.items():
f.write(key + '!' + value)
f.write("\n")
f.close()
You just had to remove the newline from each line of the file by adding [:-1].

replace line if found or append - python

I have text that is key-value pairs separated by '='. I would like to replace the line if the key matches. if not, i would like to append it at the bottom. I've tried several ways, including:
def split_command_key_and_value(command):
if '=' in command:
command2 = command.split('=')
return command2
def test(command, path):
command2 = split_command_key_and_value(command)
pattern = command2[0]
myfile = open(path,'r') # open file handle for read
# use r'', you don't need to replace '\' with '/'
result = open(path, 'w') # open file handle for write
for line in myfile:
line = line.strip() # it's always a good behave to strip what you read from files
if pattern in line:
line = command # if match, replace line
result.write(line) # write every line
myfile.close() # don't forget to close file handle
result.close()
I know the above is just to replace text, but it deletes the text in the file, and I can't see why. Could someone point me in the right direction?
Thanks
Update:
I'm almost there, but some of my lines have similar keys, so mutiple lines are matching when only 1 should. I've tried to incorporate a regex boundary in my loop with no luck. My code is below. Does anyone have a suggestion?
There is some text in the file that isn't key-value, so I would like to skip that.
def modify(self, name, value):
comb = name + ' ' + '=' + ' ' + value + '\n'
with open('/file/', 'w') as tmpstream:
with open('/file/', 'r') as stream:
for line in stream:
if setting_name in line:
tmpstream.write(comb)
else:
tmpstream.write(line)
I think I got it. See code below.
def modify(self, name, value):
comb = name + ' ' + '=' + ' ' + value + '\n'
mylist = []
with open('/file/', 'w') as tmpstream:
with open('/file/', 'r') as stream:
for line in stream:
a = line.split()
b = re.compile('\\b'+name+'\\b')
if len(a) > 0:
if b.search(a[0]):
tmpstream.write(comb)
else:
tmpstream.write(line)
I spoke too soon. It stops at the key-value I provide. So, it only writes one line, and doesn't write the lines that don't match.
def modify(name, value):
comb = name + ' ' + '=' + ' ' + value + '\n'
mylist = []
with open('/file1', 'w') as tmpstream:
with open('/file2', 'r') as stream:
for line in stream:
a = line.split()
b = re.compile('\\b'+name+'\\b')
if len(a) > 0:
if b.search(a[0]):
tmpstream.write(comb)
else:
tmpstream.write(line)
Can anyone see the issue?
Because when you open file for writing
result = open(path, 'w') # open file handle for write
you just erase it content. Try to write in different file and after all work done replace old file with new one. Or read all data into memory and then process it and write to file.
with open(path) as f:
data = f.read()
with open(path, 'w') as f:
for l in data:
# make job here
first of all you are reading an writing the same file ...
you could first read it all and the write line by line
with open(path,'r') as f:
myfile = f.read() # read everything in the variable "myfile"
result = open(path, 'w') # open file handle for write
for line in myfile.splitlines(): # process the original file content 1 line at a time
# as before
I strongly recommend reading python's documentation on how to read and write files.
If you open an existing file in write-mode open(path, 'w'), its content will be erased:
mode can be (...) 'w' for only writing (an existing file with the same name will be erased)
To replace a line in python you can have a look at this: Search and replace a line in a file in Python
Here is one the solutions provided there adapted to your context (tested for python3):
from tempfile import mkstemp
from shutil import move
from os import close
def test(filepath, command):
# Split command into key/value
key, _ = command.split('=')
matched_key = False
# Create a temporary file
fh, tmp_absolute_path = mkstemp()
with open(tmp_absolute_path, 'w') as tmp_stream:
with open(filepath, 'r') as stream:
for line in stream:
if key in line:
matched_key = True
tmp_stream.write(command + '\n')
else:
tmp_stream.write(line)
if not matched_key:
tmp_stream.write(command + '\n')
close(fh)
move(tmp_absolute_path, filepath)
Note that with the code above every line that matches key (key=blob or blob=key) will be replaced.

Code won't append data from a file to a list

For some reason I can't append the lines of my file to an empty list. "data1.txt" is just a file full of lines and lines of numbers. Calling this function returns an empty list.
filename = 'data1.txt'
def get_data(filename):
with open(filename, 'r') as qfile:
data = qfile.read().splitlines()
float_list = []
for line in data:
float_list.append(float(line))
return float_list
>>> def get_data(filename):
... with open(filename, 'r') as qfile:
... return map(float, qfile)
try with
filename = 'data1.txt'
def get_data(filename):
with open(filename, 'r') as qfile:
float_list = []
for line in qfile:
float_list.append(float(line))
return float_list
Note: you have a few problems in your code in terms of mixed indentation (spaces and tabs)

How to add a copy of each line in a txt (containing two parts separated by a particular symbol) with the order of the two parts inverted?

I have txt with a number of lines (x#y). Each file has two parts (x, y) separated by a particular symbol (#). How would a python script that reads each line in a txt and adds a new line under each existing line, where the order of the two parts (x#y) is inverted (y#x).
What I'm trying to do presented as input/output:
INPUT:
x1#y1
x2#y2
x3#y3
OUTPUT:
x1#y1
y1#x1
x2#y2
y2#x2
x3#y3
y3#x3
How can this be done with python?
Here's one way:
infilename = 'in.dat'
outfilename = 'out.dat'
sep = '#'
with open(infilename) as infile, open(outfilename,'w') as outfile:
for line in infile:
split = line.strip().partition(sep)
outfile.write(line)
outfile.write(''.join(reversed(split)) + '\n')
and then
~/coding$ cat in.dat
x1#y1
x2#y2
x3#y3
~/coding$ python inverter.py
~/coding$ cat out.dat
x1#y1
y1#x1
x2#y2
y2#x2
x3#y3
y3#x3
Assumes the name of your file is bar.txt, and that you want to write it back to bar.txt. It also does no error checking nor cares about memory usage.
if __name__ == "__main__":
myfile = open("bar.txt", "rb")
lines = myfile.readlines()
myfile.close()
myfile = open("bar.txt", "wb")
for l in lines:
ls = l.strip()
myfile.write(ls + "\n")
lsplit = ls.split("#")
myfile.write(lsplit[1] + "#" + lsplit[0] + "\n")
myfile.close()
There are cleaner ways to do this, but you could use something like:
f = open('my_file.txt', 'r')
lines = f.readlines()
f.close()
outfile = open('my_file2.txt', 'w')
# write each line, followed by flipped line
for line in lines:
outfile.write('%s\n' % line)
parts = line.split('#')
outfile.write('%s#%s\n' % [parts[1], parts[0]])
outfile.close()
You can use open and read function to read your file and than use this function,
>>> st = "x1#y1"
>>> def myfunc(string):
... mylist = re.split(r'(#)',string)
... mylist.reverse()
... print "".join(mylist), string
...
>>> myfunc(st)
y1#x1 x1#y1
and than use write to write the strings into your new file.
def swap(delimiter="#", input="input.txt", ouput="output.txt"):
with open(input, "r") as input_file, open(ouput, "w") as output_file:
for line in input_file:
line = line.strip()
output_line = delimiter.join(reversed(line.split(delimiter)))
output_file.write(line+"\n")
output_file.write(output_line+"\n")
swap()
Riffing on #DSM:
with open(infilename) as infile, open(outfilename, 'w') as outfile:
lines = [line.rstrip() for line in infile]
outfile.write("\n".join("%s\n%s%s%s" (line, y, sep, x)
for line in lines
for x, y in line.split(sep)) + "\n")
lines could also be a generator statement instead of a list comprehension:
lines = (line.rstrip() for line in infile)
Later: I did not realize until now that OP wanted the original line followed by the reversed line. Adjusted accordingly.

Categories