Python - Additional backslash is added to file path - python

I have some text file with these lines:
Zip=false
Run=false
Copy=true
FileName=c:\test\test.doc
Now I need to load this text file, change some values and write back to same text file.
So I load it to a dictionary, change values on the dictionary and write back.
The problem is that that backslashes in the FileName path are being duplicate and in the new file I get FileName=c:\test\test.doc.
Here is the dictionary creation:
def create_dictionary(filename):
try:
file = open(filename, 'r')
except:
print("Error " + filename + " not found or path is incorrect")
else:
contents = file.read().splitlines()
properties_dict = {}
for line in contents:
if not line.startswith("#") and line.strip():
# print (line)
x, y = line.split("=")
properties_dict[x] = [y]
return properties_dict
Here is writing back to the file
# Update the properties file with updated dictionary
fo = open(properties_file, "w")
for k, v in dic.items():
print(str(k), str(v))
fo.write(str(k) + '=' + str(v).strip("[]'") + '\n')
fo.close()

This seems to be working:
def create_dictionary(file_name):
try:
properties_dict = {}
with open(file_name, "r") as file:
contents = file.read().splitlines()
for line in contents:
if not line.startswith("#") and line.strip():
property_name, property_value = line.split("=")
properties_dict[property_name] = property_value
return properties_dict
except FileNotFoundError:
print(f"Error {file_name} not found or path is incorrect")
def dict_to_file(properties_dict, file_name):
try:
file_dirname = os.path.dirname(file_name)
if not os.path.exists(file_dirname):
os.makedirs(file_dirname)
except FileNotFoundError: # in case the file is in the same directory and "./" was not added to the path
pass
with open(file_name, "w") as file:
for property_name, property_value in properties_dict.items():
file.write(f"{property_name}={property_value}\n")
properties_dict = create_dictionary("./asd.txt")
dict_to_file(properties_dict, "./bsd.txt")
Since, there was a request for more explanations, I am editing this post.
Actually the critical part is not file.write(f"...") as #pktl2k pointed out. The critical part is changing properties_dict[x] = [y] to properties_dict[x] = y.
In Python strings, when you want to escape special characters you use a backslash ( \ ). The FileName parameter in your file has one of those special characters which is also a backslash (FileName=c:\test\test.doc). Thus, when you read this file, Python stores it as string as:
"c:\\test\\test.doc"
Which is totally normal. And when you want to write this string back to a file, you will get your desired output ( no double backslashes ). However, in your code, you do not have this value as a string. You have it as a list that is holding this value as string. When you call str built-in function on a list (which by the way is a built-in class), list class' __repr__ function is called (actually __str__ is called but in list __str__ calls __repr__ as far as I know, but let's not go so much into details of these functions. See this link if you want to learn more about it) to get a string representation of your list. In this process, all your list is converted to a string with all of its elements as it is. Then you get rid of some characters in this string representation using strip("[]'"), this is the actual cause of your problem.
Now, why did I write everything from the beginning and not only the part that is important as #pktl2k kindly asked. The reason is because if you noticed in create_dictionary function the author forgot to close the file using file.close(). This is a common problem and that's why there is a syntax like with open(....). I wanted to emphasis that: it is better to use with open(...) syntax whenever we would like to manipulate contents of a file. I could also write this as a small note as well, but I think it is better with this way (so it is a personal preference).

Related

replace new line in a different file with an underscore (without using with)

I posted a question yesterday in similar regards to this but didn't quite gauge the response I wanted because I wasn't specific enough. Basically the function takes a .txt file as the argument and returns a string with all \n characters replaced with an '_' on the same line. I want to do this without using WITH. I thought I did this correctly but when I run it and check the file, nothing has changed. Any pointers?
This is what I did:
def one_line(filename):
wordfile = open(filename)
text_str = wordfile.read().replace("\n", "_")
wordfile.close()
return text_str
one_line("words.txt")
but to no avail. I open the text file and it remains the same.
The contents of the textfile are:
I like to eat
pancakes every day
and the output that's supposed to be shown is:
>>> one_line("words.txt")
’I like to eat_pancakes every day_’
The fileinput module in the Python standard library allows you to do this in one fell swoop.
import fileinput
for line in fileinput.input(filename, inplace=True):
line = line.replace('\n', '_')
print(line, end='')
The requirement to avoid a with statement is trivial but rather pointless. Anything which looks like
with open(filename) as handle:
stuff
can simply be rewritten as
try:
handle = open(filename)
stuff
finally:
handle.close()
If you take out the try/finally you have a bug which leaves handle open if an error happens. The purpose of the with context manager for open() is to simplify this common use case.
You are missing some steps. After you obtain the updated string, you need to write it back to the file, example below without using with
def one_line(filename):
wordfile = open(filename)
text_str = wordfile.read().replace("\n", "_")
wordfile.close()
return text_str
def write_line(s):
# Open the file in write mode
wordfile = open("words.txt", 'w')
# Write the updated string to the file
wordfile.write(s)
# Close the file
wordfile.close()
s = one_line("words.txt")
write_line(s)
Or using with
with open("file.txt",'w') as wordfile:
#Write the updated string to the file
wordfile.write(s)
with pathlib you could achieve what you want this way:
from pathlib import Path
path = Path(filename)
contents = path.read_text()
contents = contents.replace("\n", "_")
path.write_text(contents)

Read all the text files in a folder and change a character in a string if it presents

I have a folder with csv formated documents with a .arw extension. Files are named as 1.arw, 2.arw, 3.arw ... etc.
I would like to write a code that reads all the files, checks and replaces the forwardslash / with a dash -. And finally creates new files with the replaced character.
The code I wrote as follows:
for i in range(1,6):
my_file=open("/path/"+str(i)+".arw", "r+")
str=my_file.read()
if "/" not in str:
print("There is no forwardslash")
else:
str_new = str.replace("/","-")
print(str_new)
f = open("/path/new"+str(i)+".arw", "w")
f.write(str_new)
my_file.close()
But I get an error saying:
'str' object is not callable.
How can I make it work for all the files in a folder? Apparently my for loop does not work.
The actual error is that you are replacing the built-in str with your own variable with the same name, then try to use the built-in str() after that.
Simply renaming the variable fixes the immediate problem, but you really want to refactor the code to avoid reading the entire file into memory.
import logging
import os
for i in range(1,6):
seen_slash = False
input_filename = "/path/"+str(i)+".arw"
output_filename = "/path/new"+str(i)+".arw"
with open(input_filename, "r+") as input, open(output_filename, "w") as output:
for line in input:
if not seen_slash and "/" in line:
seen_slash = True
line_new = line.replace("/","-")
print(line_new.rstrip('\n')) # don't duplicate newline
output.write(line_new)
if not seen_slash:
logging.warn("{0}: No slash found".format(input_filename))
os.unlink(output_filename)
Using logging instead of print for error messages helps because you keep standard output (the print output) separate from the diagnostics (the logging output). Notice also how the diagnostic message includes the name of the file we found the problem in.
Going back and deleting the output filename when you have examined the entire input file and not found any slashes is a mild wart, but should typically be more efficient.
This is how I would do it:
for i in range(1,6):
with open((str(i)+'.arw'), 'r') as f:
data = f.readlines()
for element in data:
element.replace('/', '-')
f.close()
with open((str(i)+'.arw'), 'w') as f:
for element in data:
f.write(element)
f.close()
this is assuming from your post that you know that you have 6 files
if you don't know how many files you have you can use the OS module to find the files in the directory.

Python Writing data to output File

def fileCounter():
infile = open('words.txt','r') # Open the source file
outfile = open('File_Results.txt','w')
data = infile.read()
lineCount = len(data.split('\n'))
wordCount = len(data.split())
charCount = len(data)
results = print(lineCount,wordCount,charCount)
infile.close()
outfile.write()
outfile.close()
fileCounter()
I'm new to coding and this is my first time working with files. How do I write results in my outfield. I keep getting this error - TypeError: write() argument must be str, not None
You need to write something. Something goes between the parentheses for outfile.write(). My guess is that you want something like this:
outfile.write("{} {} {}".format(lineCount, wordCount, charCount))
Your result = print(...) doesn't save anything. It prints to your console.
Another approach would be redirecting your prints to your file:
from contextlib import redirect_stdout
def fileCounter():
with (open('words.txt','r') as infile, open('File_Results.txt','w') as outfile):
data = infile.read()
lineCount = len(data.split('\n'))
wordCount = len(data.split())
charCount = len(data)
with redirect_stdout(outfile):
print(lineCount,wordCount,charCount)
fileCounter()
Note that I also used context managers to automatically handle opening and closing files. This approach is safer because it'll close the files (and stop redirecting STDOUT) even if an exception occurs.
There is no argument to your outfile.write() function. There needs to be some content to be written to the file, that needs to be passed as parameter to the function.
For Example:
# To write 'I am new to Python'
outfile.write('I am new to Python')
the argument to the write function must be a string.
if this line
results = print(lineCount,wordCount,charCount)
prints the stuff you want to have in the output file, you might do something like
results = "%s, %s, %s" % (lineCount,wordCount,charCount)
outfile.write(results)
outfile.close()
There are no arguments in outfile.write() so it writes nothing.
I assume you want to write the data of infile in outfile, so you do the following:
outfile.write(lineCount)
outfile.write(wordCount)
outfile.write(charCount)
In outfile.write() you wish to include whatever you're writing to file. In this case, you could do something like:
#put results into a list
results = [lineCount, wordCount, charCount]
#print results
print(results)
#write results to a file
outfile.write(",".join(results))
Two things in your code that are interesting. First, as far as I'm aware, print returns None so results in your current code is None. Second, in the corrected rendition, results is a list but in order to write it to file you need to convert it to a string. We do that by joining the elements in the list, in this case with a comma.

python clear content writing on same file

I am a newbie to python. I have a code in which I must write the contents again to my same file,but when I do it it clears my content.Please help to fix it.
How should I modify my code such that the contents will be written back on the same file?
My code:
import re
numbers = {}
with open('1.txt') as f,open('11.txt', 'w') as f1:
for line in f:
row = re.split(r'(\d+)', line.strip())
words = tuple(row[::2])
if words not in numbers:
numbers[words] = [int(n) for n in row[1::2]]
numbers[words] = [n+1 for n in numbers[words]]
row[1::2] = map(str, numbers[words])
indentation = (re.match(r"\s*", line).group())
print (indentation + ''.join(row))
f1.write(indentation + ''.join(row) + '\n')
In general, it's a bad idea to write over a file you're still processing (or change a data structure over which you are iterating). It can be done...but it requires much care, and there is little safety or restart-ability should something go wrong in the middle (an error, a power failure, etc.)
A better approach is to write a clean new file, then rename it to the old name. For example:
import re
import os
filename = '1.txt'
tempname = "temp{0}_{1}".format(os.getpid(), filename)
numbers = {}
with open(filename) as f, open(tempname, 'w') as f1:
# ... file processing as before
os.rename(tempname, filename)
Here I've dropped filenames (both original and temporary) into variables, so they can be easily referred to multiple times or changed. This also prepares for the moment when you hoist this code into a function (as part of a larger program), as opposed to making it the main line of your program.
You don't strictly need the temporary name to embed the process id, but it's a standard way of making sure the temp file is uniquely named (temp32939_1.txt vs temp_1.txt or tempfile.txt, say).
It may also be helpful to create backups of the files as they were before processing. In which case, before the os.rename(tempname, filename) you can drop in code to move the original data to a safer location or a backup name. E.g.:
backupname = filename + ".bak"
os.rename(filename, backupname)
os.rename(tempname, filename)
While beyond the scope of this question, if you used a read-process-overwrite strategy frequently, it would be possible to create a separate module that abstracted these file-handling details away from your processing code. Here is an example.
Use
open('11.txt', 'a')
To append to the file instead of w for writing (a new or overwriting a file).
If you want to read and modify file in one time use "r+' mode.
f=file('/path/to/file.txt', 'r+')
content=f.read()
content=content.replace('oldstring', 'newstring') #for example change some substring in whole file
f.seek(0) #move to beginning of file
f.write(content)
f.truncate() #clear file conent "tail" on disk if new content shorter then old
f.close()

Python: replacing data in a CSV file

Hello i am attempting to adjust a CSV file using Python but my out put is a little off and I can't figure out why.
in_file = open(out, "rb")
fout = "DomainWatchlist.csv"
fin_out_file = open(fout, "wb")
csv_writer2 = csv.writer(fin_out_file, quoting=csv.QUOTE_MINIMAL)
for item in in_file:
if "[.]" in item:
csv_writer2.writerow([item.replace("[.]", ".")])
elif "[dot]" in item:
csv_writer2.writerow([item.replace("[dot]", ".")])
else:
csv_writer2.writerow([item])
in_file.close
fin_out_file.close
The input file contains data that looks like this:
bluecreatureoftheseas.com
12rafvwe[dot]co[dot]cc
12rafvwe[dot]co[dot]cc
404page[dot]co[dot]cc
abalamahala[dot]co[dot]cc
abtarataha[dot]co[dot]cc
adoraath[dot]cz[dot]cc
adoranaya[dot]cz[dot]cc
afnffnjq[dot]co[dot]cc
aftermorningstar[dot]co[dot]cc
I am attempting to fix this data but it comes out looking like this:
"12rafvwe.co.cc
"
"12rafvwe.co.cc
"
"404page.co.cc
"
"abalamahala.co.cc
"
"abtarataha.co.cc
"
"adoraath.cz.cc
"
"adoranaya.cz.cc
"
"afnffnjq.co.cc
"
"aftermorningstar.co.cc
"
"aftrafsudalitf.co.cc
"
"agamafym.cz.cc
"
"agamakus.vv.cc
Why does this create the extra quotes and then add a carriage return?
The reason you're getting a newline is that for item in in_file: iterates over each line in in_file, without stripping the newline. You don't strip the newline anywhere. So it's still there in the single string in the list you pass to writerow.
The reason you're getting quotes is that in CSV, strings with special characters—like newlines—have to be either escaped or quoted. There are different "dialect options" you can set to control that, but by default, it tries to use quoting instead of escaping.
So, the solution is something like this:
for item in in_file:
item = item.rstrip()
# rest of your code
There are some other problems with your code, as well as some ways you're making things more complicated than they need to be.
First, in_file.close does not close the file. You're not calling the function, just referring to it as a function object. You need parentheses to call a function in Python.
But an even simpler way to handle closing files is to use a with statement.
You only have a single column, so there is no need to use the csv module at all. Just fin_out_file.write would work just fine.
You also probably don't want to use binary mode here. If you have a good reason for doing so, that's fine, but if you don't know why you're using it, don't use it.
You don't need to check whether a substring exists before replace-ing it. If you call 'abc'.replace('n', 'N'), it will just harmlessly return 'abc'. All you're doing is writing twice as much code, and making Python search each string twice in a row.
Putting this all together, here's the whole thing in three lines:
with open(out) as in_file, open(fout, 'w') as out_file:
for line in in_file:
out_file.write(line.replace("[.]", ".").replace("[dot]", "."))
a bit OT but perl was built for this
$ perl -i -ple 's/\[dot\]/./g' filename
will do the job, including saving the new file on the oldfilename.

Categories

Resources