How to modify specific line in sql file? - python

I am trying to modify a line in sql file in a directory.
Currently have written the code which navigates to files directory according to user input .
each sql file in that dir has these 2 lines:
--liquibase formatted sql
--changeset Jack:1 runOnChange:true splitStatements:false stripComments:false
I am trying to do is loop through all files and I want to change-set every-time the script runs.
so those 2 lines will look like this :
--liquibase formatted sql
--changeset Ryan:2 runOnChange:true splitStatements:false stripComments:false
The part I want to change in line is constant but the content is different for each file like in other file it will be Jie:6 I want to replace that with Priyal:7. So the name part is the person who is running the script and the number after : is incremented
Is there a cleaner way to achieve this :
This is just sample code I have which configures path and everything :
anbpath = os.path.abspath("copy_views.py")
print(anbpath)
sqldir = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', 'database'))
path_to_views = sqldir+"/sql/edm/changes/"+source_release_version+"/mutable/view"
print(path_to_views)
destdir = os.path.abspath(os.path.join(os.path.dirname( __file__ ),'..', 'database'))
path_to_dest_rel_ver = destdir+"/sql/edm/changes/"+dest_release_version
path_to_dest = path_to_dest_rel_ver+"/mutable/view"
I will traverse all files in path_to_dest using os.walk

If your file is called "file.txt" and if the name is constant then what you are looking for is
# Read the contents of file
with open("file.txt", 'r') as fp:
lines = fp.readlines()
#Idendify tokens and numbers with in them and increment them
words = lines[1].split()
tokens = words[1].split(":")
words[1] = "name{0}:{1}".format(int(tokens[0][4:])+1, int(tokens[1])+1)
lines[1] = ' '.join(words)
# Write back the updated lines
with open("file.txt", 'w') as fp:
fp.writelines(lines)
Initial content of file
"--liquibase formatted sql",
"--changeset name3:21 runOnChange:true splitStatements:false stripComments:false"]
Afer modification
"--liquibase formatted sql",
"--changeset name4:22 runOnChange:true splitStatements:false stripComments:false"]
However, if the name is not constant then we can still split the token at ":" to indentify the number after ":" but to indentify the number ending at the name we will have to use regex.

You can use regex to solve this:
The following code will replace the string "name1:1" by "name2:2" if it finds the correct sequence and preserve the rest of the line:
import re
# read the file, line by line and then:
line_fixed = re.sub(r"(--changeset )name1:1(.*)", r"\1name2:2\2", line)
# then save the fixed line to a temporary file until you read all file

Here's a way to do it with regular expressions:
import re
lines = [
"--liquibase formatted sql",
"--changeset Jack:2 runOnChange:true splitStatements:false stripComments:false",
"--liquibase formatted sql",
"--changeset Ryan:6 runOnChange:true splitStatements:false stripComments:false",
# etc ...
]
def update_line(line):
p = re.compile(r'--changeset (.+):(\d+) runOnChange')
matches = p.match(line)
if not matches:
return line
else:
replacement = '--changeset {}:{} runOnChange'.format(matches.group(1),
int(matches.group(2))+1)
return p.sub(replacement, line)
for line in lines:
updated_line = update_line(line)
print(repr(updated_line))
Output:
'--liquibase formatted sql'
'--changeset Jack:3 runOnChange:true splitStatements:false stripComments:false'
'--liquibase formatted sql'
'--changeset Ryan:7 runOnChange:true splitStatements:false stripComments:false'

Related

How to add quotes in the file

I have file below
123,PEN BOOK
124,BALL
125,BOOK
126,PENCIL BOOK
I need to add quotes
Expected out
"123","PEN BOOK"
"124","BALL"
"125","BOOK"
"126","PENCIL BOOK"
Assume you have a file test.txt with the following content:
123,PEN
124,BALL
125,BOOK
126,PENCIL
You can use a code like the following, to create a temp file with the content with quotes and replace the original file:
import os
with open("test.txt") as i: # open file for reading, i = input file
with open("temp.txt", "w") as o: # open temp file in write mode, o = output
for l in i: # read each line
o.write('"{}","{}"\n'.format(l.split(',')[0],l.split(',')[1].split('\n')[0]))
os.remove('test.txt') # remove the old file
os.rename('temp.txt','test.txt') # resave the temp file as the new file
Output:
"123","PEN"
"124","BALL"
"125","BOOK"
"126","PENCIL"
I've updated my answer to cover additional case of text containing spaces.
Seeing as you have a regex tag in your question, you can use something like this:
import re
text = """123,PEN
124,BALL
125,BOOK
126,PENCIL
123,PEN BOOK"""
new_text = re.sub(r'(\d+),([\w\s]+)$', r'"\1","\2"', text, flags=re.M)

Reading a textfile into a String

I'm just starting to learn python and have a textfile that looks like this:
Hello
World
Hello
World
And I want to add the numbers '55' to the beggining and end of every string that starts with 'hello'
The numbers '66' to the beggining and every of every string that starts with 'World'
etc
So my final file should look like this:
55Hello55
66World66
55Hello55
66World66
I'm reading the file in all at once, storing it in a string, and then trying to append accordingly
fp = open("test.txt","r")
strHolder = fp.read()
print(strHolder)
if 'Hello' in strHolder:
strHolder = '55' + strHolder + '55'
if 'World' in strHolder:
strHolder = '66' + strHolder + '66'
print(strHolder)
fp.close()
However, my string values '55' and '66' are always being added to the front of the file and end of the file, not the front of a certain string and to the end of the string, where I get this output of the string:
6655Hello
World
Hello
World
5566
Any help would be much appreciated.
You are reading the whole file at once with .read().
You can read it line by line in a for loop.
new_file = []
fp = open("test.txt", "r")
for line in fp:
line = line.rstrip("\n") # The string ends in a newline
# str.rstrip("\n") removes newlines at the end
if "Hello" in line:
line = "55" + line + "55"
if "World" in line:
line = "66" + line + "66"
new_file.append(line)
fp.close()
new_file = "\n".join(new_file)
print(new_file)
You could do it all at once, by reading the whole file and splitting by "\n" (newline)
new_file = []
fp = open("text.txt")
fp_read = fp.read()
fp.close()
for line in fp_read.split("\n"):
if "Hello" # ...
but this would load the whole file into memory at once, while the for loop only loads line by line (So this may not work for larger files).
The behaviour of this is that if the line has "Hello" in it, it will get "55" before and after it (even if the line is " sieohfoiHellosdf ") and the same for "World", and if it has both "Hello" and "World" (e.g. "Hello, World!" or "asdifhoasdfhHellosdjfhsodWorldosadh") it will get "6655" before and after it.
Just as a side note: You should use with to open a file as it makes sure that the file is closed later.
new_file = []
with open("test.txt") as fp: # "r" mode is default
for line in fp:
line = line.rstrip("\n")
if "Hello" in line:
line = "55" + line + "55"
if "World" in line:
line = "66" + line + "66"
new_file.append(line)
new_file = "\n".join(new_file)
print(new_file)
You need to iterate over each line of the file in order to get the desired result. In your code you are using .read(), instead use .readlines() to get list of all lines.
Below is the sample code:
lines = []
with open("test.txt", "r") as f:
for line in f.readlines(): # < Iterate over each line
if line.startswith("Hello"): # <-- check if line starts with "Hello"
line = "55{}55".format(line)
elif line.startswith("World"):
line = "66{}66".format(line)
lines.append(line)
print "\n".join(lines)
Why to use with? Check Python doc:
The ‘with‘ statement clarifies code that previously would use try...finally blocks to ensure that clean-up code is executed. In this section, I’ll discuss the statement as it will commonly be used. In the next section, I’ll examine the implementation details and show how to write objects for use with this statement.
The ‘with‘ statement is a control-flow structure whose basic structure is:
with expression [as variable]: with-block
The expression is evaluated, and it should result in an object that supports the context management protocol (that is, has enter() and exit() methods).
once you have read the file:
read_file = read_file.replace('hello','55hello55')
It'll replace all hellos with 55hello55
and use with open(text.txt, 'r' ) as file_hndler:
To read a text file, I recommend the following way which is compatible with Python 2 & 3:
import io
with io.open("test", mode="r", encoding="utf8") as fd:
...
Here, I make the assumption that your file use uft8 encoding.
Using a with statement make sure the file is closed at the end of reading even if a error occurs (an exception). To learn more about context manager, take a look at the Context Library.
There are several ways to read a text file:
read the whole file with: fd.read(), or
read line by line with a loop: for line in fd.
If you read the whole file, you'll need to split the lines (see str.splitlines. Here are the two solutions:
with io.open("test", mode="r", encoding="utf8") as fd:
content = fd.read()
for line in content.splilines():
if "Hello" in line:
print("55" + line + "55")
if "World" in line:
print("66" + line + "66")
Or
with io.open("test", mode="r", encoding="utf8") as fd:
for line in content.splilines():
line = line[:-1]
if "Hello" in line:
print("55" + line + "55")
if "World" in line:
print("66" + line + "66")
If you need to write the result in another file you can open the output file in write mode and use print(thing, file=out) as follow:
with io.open("test", mode="r", encoding="utf8") as fd:
with io.open("test", mode="w", encoding="utf8") as out:
for line in content.splilines():
line = line[:-1]
if "Hello" in line:
print("55" + line + "55", file=out)
if "World" in line:
print("66" + line + "66", file=out)
If you use Python 2, you'll need the following directive to use the print function:
from __future__ import print_function

Cleaning up a messy data file to a more readable format in Python?

I have a text file (heavily modified for this example) which has some data that I want to extract and do some calculations with it. However the text file is extremely messy, so I'm trying to clean it up and write it out to new files first.
Here is the .txt file I'm working with: http://textuploader.com/5elql
I am trying to extract the data which is under the titles (called “Important title”). The only possible way to do that is to first locate a string which always occurs in the file, and its called “DATASET” because all the mess above and below the important data will cover an arbitrary number of lines, difficult to remove manually. Once that’s done I want to store the data in separate files so that it is easier to analyse like this:
http://textuploader.com/5elqw
The file names will be concatenated with the title + the date.
Here is what I have tried so far
with open("example.txt") as file:
for line in file:
if line.startswith('DATASET:'):
fileTitle = line[9:]
if line.startswith("DATE:"):
fileDate = line[:]
print(fileTitle+fileDate)
OUTPUT
IMPORTANT TITLE 1
DATE: 12/30/2015
IMPORTANT TITLE 2
DATE: 01/03/2016
So it appears my loop manages to locate the lines where the titles inside the file are and print them out. But this is where I run out of steam. I have no idea on how to extract the data under those titles from there onwards. I have tried using file.readlines() but it outputs all the mess that is in between Important Title 1 and Important Title 2.
Any advice on how I can read all the data under the titles and output them into separate files? Thanks for your time.
You could use regex.
import re
pattern = r"(\s+X\s+Y\s*)|(\s*\d+\s+\d+\s*)"
prog = re.compile(pattern)
with open("example.txt") as file:
cur_filename = ''
content = ""
for line in file:
if line.startswith('DATASET:'):
fileTitle = line[9:]
elif line.startswith("DATE:"):
fileDate = line[6:]
cur_filename = (fileTitle.strip() + fileDate.strip()).replace('/', '-')
print(cur_filename)
content_title = fileTitle + line
elif prog.match(line):
content += line
elif cur_filename and content:
with open(cur_filename, 'w') as fp:
fp.write(content_title)
fp.write(content)
cur_filename = ''
content = ''
I don't know exactly how you want to store your data but assuming you want a dictionary you could use regex to check if the incoming line matched the pattern, then because fileTitle isn't global you could use that as the key and add the values. I also added rstrip('\r\n') to remove the newline characters after fileTitle.
import re
#if you don't want to store the X and Y, just use re.compile('\d\s+\d+')
p = re.compile('(\d\s+\d+)|(X\s+Y)')
data={}
with open("input.txt") as file:
for line in file:
if line.startswith('DATASET:'):
fileTitle = line[9:].rstrip('\r\n')
if line.startswith("DATE:"):
fileDate = line[:]
print(fileTitle+fileDate)
if p.match(line):
if fileTitle not in data:
data[fileTitle]=[]
line=line.rstrip('\r\n')
data[fileTitle].append(line.split('\t'))
if len(data[fileTitle][len(data[fileTitle])-1]) == 3:
data[fileTitle][len(data[fileTitle])-1].pop()
print data
Yet another regex solution:
sep = '*************************\n'
pattern = r'DATASET[^%]*'
good_stuff = re.compile(pattern)
pattern = r'^DATASET: (.*?)$'
title = re.compile(pattern, flags = re.MULTILINE)
pattern = r'^DATE: (.*?)$'
date = re.compile(pattern, flags = re.MULTILINE)
with open(r'foo.txt') as f:
data = f.read()
for match in good_stuff.finditer(data):
data = match.group()
important_title = title.search(data).group(1)
important_date = date.search(data).group(1)
important_date = important_date.replace(r'/', '-')
fname = important_title + important_date + '.txt'
print(sep, fname)
print(data)
##with open(fname, 'w') as f:
## f.write(data)

Save output from biopython object into a file?

Here i have a code written to extract "locus_tag" of gene using "id". How can i save the output from this into a file in a tab seperated format????code adopted and modified https://www.biostars.org/p/110284/
from Bio import SeqIO
foo = open("geneid.txt")
lines = foo.read().splitlines()
genbank_file = open("example.gbk")
for record in SeqIO.parse(genbank_file, "genbank"):
for f in record.features:
if f.type == "CDS" and "protein_id" in f.qualifiers:
protein_id = f.qualifiers["protein_id"][0]
if protein_id in lines:
print f.qualifiers["protein_id"][0],f.qualifiers["locus_tag"][0]
Try adding something like this -- but you will need to make certain the indentations are correct with the code that you have already written.
with open(your_outputFileName, 'w') as outputFile:
string = '\t'.join([f.qualifiers['protein_id'][0],f.qualifiers['locus_tag'][0]])
outputFile.write(string + '\n')
You should also consider opening your initial file using "with". This will automatically close the file when you are done with it -- otherwise -- be certain to close the file (e.g., foo.close()).
for record in SeqIO.parse(genbank_file, 'genbank'):
for f in record.features:
if f.type == 'CDS' and 'protein_id' in f.qualifiers:
protein_id = f.qualifiers['protein_id'][0]
if protein_id in lines:
print f.qualifiers['protein_id'][0],f.qualifiers['locus_tag'][0]
with open('your_outputFileName', 'w') as outputFile:
string = '\t'.join([f.qualifiers['protein_id'][0],f.qualifiers['locus_tag'][0]]) + '\n'
outputFile.write(string)

How to search and replace text in a file?

How do I search and replace text in a file using Python 3?
Here is my code:
import os
import sys
import fileinput
print ("Text to search for:")
textToSearch = input( "> " )
print ("Text to replace it with:")
textToReplace = input( "> " )
print ("File to perform Search-Replace on:")
fileToSearch = input( "> " )
#fileToSearch = 'D:\dummy1.txt'
tempFile = open( fileToSearch, 'r+' )
for line in fileinput.input( fileToSearch ):
if textToSearch in line :
print('Match Found')
else:
print('Match Not Found!!')
tempFile.write( line.replace( textToSearch, textToReplace ) )
tempFile.close()
input( '\n\n Press Enter to exit...' )
Input file:
hi this is abcd hi this is abcd
This is dummy text file.
This is how search and replace works abcd
When I search and replace 'ram' by 'abcd' in above input file, it works as a charm. But when I do it vice-versa i.e. replacing 'abcd' by 'ram', some junk characters are left at the end.
Replacing 'abcd' by 'ram'
hi this is ram hi this is ram
This is dummy text file.
This is how search and replace works rambcd
As pointed out by michaelb958, you cannot replace in place with data of a different length because this will put the rest of the sections out of place. I disagree with the other posters suggesting you read from one file and write to another. Instead, I would read the file into memory, fix the data up, and then write it out to the same file in a separate step.
# Read in the file
with open('file.txt', 'r') as file :
filedata = file.read()
# Replace the target string
filedata = filedata.replace('abcd', 'ram')
# Write the file out again
with open('file.txt', 'w') as file:
file.write(filedata)
Unless you've got a massive file to work with which is too big to load into memory in one go, or you are concerned about potential data loss if the process is interrupted during the second step in which you write data to the file.
fileinput already supports inplace editing. It redirects stdout to the file in this case:
#!/usr/bin/env python3
import fileinput
with fileinput.FileInput(filename, inplace=True, backup='.bak') as file:
for line in file:
print(line.replace(text_to_search, replacement_text), end='')
As Jack Aidley had posted and J.F. Sebastian pointed out, this code will not work:
# Read in the file
filedata = None
with file = open('file.txt', 'r') :
filedata = file.read()
# Replace the target string
filedata.replace('ram', 'abcd')
# Write the file out again
with file = open('file.txt', 'w') :
file.write(filedata)`
But this code WILL work (I've tested it):
f = open(filein,'r')
filedata = f.read()
f.close()
newdata = filedata.replace("old data","new data")
f = open(fileout,'w')
f.write(newdata)
f.close()
Using this method, filein and fileout can be the same file, because Python 3.3 will overwrite the file upon opening for write.
You can do the replacement like this
f1 = open('file1.txt', 'r')
f2 = open('file2.txt', 'w')
for line in f1:
f2.write(line.replace('old_text', 'new_text'))
f1.close()
f2.close()
You can also use pathlib.
from pathlib2 import Path
path = Path(file_to_search)
text = path.read_text()
text = text.replace(text_to_search, replacement_text)
path.write_text(text)
(pip install python-util)
from pyutil import filereplace
filereplace("somefile.txt","abcd","ram")
Will replace all occurences of "abcd" with "ram".
The function also supports regex by specifying regex=True
from pyutil import filereplace
filereplace("somefile.txt","\\w+","ram",regex=True)
Disclaimer: I'm the author (https://github.com/MisterL2/python-util)
Open the file in read mode. Read the file in string format. Replace the text as intended. Close the file. Again open the file in write mode. Finally, write the replaced text to the same file.
try:
with open("file_name", "r+") as text_file:
texts = text_file.read()
texts = texts.replace("to_replace", "replace_string")
with open(file_name, "w") as text_file:
text_file.write(texts)
except FileNotFoundError as f:
print("Could not find the file you are trying to read.")
Late answer, but this is what I use to find and replace inside a text file:
with open("test.txt") as r:
text = r.read().replace("THIS", "THAT")
with open("test.txt", "w") as w:
w.write(text)
DEMO
With a single with block, you can search and replace your text:
with open('file.txt','r+') as f:
filedata = f.read()
filedata = filedata.replace('abc','xyz')
f.truncate(0)
f.write(filedata)
Your problem stems from reading from and writing to the same file. Rather than opening fileToSearch for writing, open an actual temporary file and then after you're done and have closed tempFile, use os.rename to move the new file over fileToSearch.
My variant, one word at a time on the entire file.
I read it into memory.
def replace_word(infile,old_word,new_word):
if not os.path.isfile(infile):
print ("Error on replace_word, not a regular file: "+infile)
sys.exit(1)
f1=open(infile,'r').read()
f2=open(infile,'w')
m=f1.replace(old_word,new_word)
f2.write(m)
Using re.subn it is possible to have more control on the substitution process, such as word splitted over two lines, case-(in)sensitive match. Further, it returns the amount of matches which can be used to avoid waste of resources if the string is not found.
import re
file = # path to file
# they can be also raw string and regex
textToSearch = r'Ha.*O' # here an example with a regex
textToReplace = 'hallo'
# read and replace
with open(file, 'r') as fd:
# sample case-insensitive find-and-replace
text, counter = re.subn(textToSearch, textToReplace, fd.read(), re.I)
# check if there is at least a match
if counter > 0:
# edit the file
with open(file, 'w') as fd:
fd.write(text)
# summary result
print(f'{counter} occurence of "{textToSearch}" were replaced with "{textToReplace}".')
Some regex:
add the re.I flag, short form of re.IGNORECASE, for a case-insensitive match
for multi-line replacement re.subn(r'\n*'.join(textToSearch), textToReplace, fd.read()), depending on the data also '\n{,1}'. Notice that for this case textToSearch must be a pure string, not a regex!
Besides the answers already mentioned, here is an explanation of why you have some random characters at the end:
You are opening the file in r+ mode, not w mode. The key difference is that w mode clears the contents of the file as soon as you open it, whereas r+ doesn't.
This means that if your file content is "123456789" and you write "www" to it, you get "www456789". It overwrites the characters with the new input, but leaves any remaining input untouched.
You can clear a section of the file contents by using truncate(<startPosition>), but you are probably best off saving the updated file content to a string first, then doing truncate(0) and writing it all at once.
Or you can use my library :D
I got the same issue. The problem is that when you load a .txt in a variable you use it like an array of string while it's an array of character.
swapString = []
with open(filepath) as f:
s = f.read()
for each in s:
swapString.append(str(each).replace('this','that'))
s = swapString
print(s)
I tried this and used readlines instead of read
with open('dummy.txt','r') as file:
list = file.readlines()
print(f'before removal {list}')
for i in list[:]:
list.remove(i)
print(f'After removal {list}')
with open('dummy.txt','w+') as f:
for i in list:
f.write(i)
you can use sed or awk or grep in python (with some restrictions). Here is a very simple example. It changes banana to bananatoothpaste in the file. You can edit and use it. ( I tested it worked...note: if you are testing under windows you should install "sed" command and set the path first)
import os
file="a.txt"
oldtext="Banana"
newtext=" BananaToothpaste"
os.system('sed -i "s/{}/{}/g" {}'.format(oldtext,newtext,file))
#print(f'sed -i "s/{oldtext}/{newtext}/g" {file}')
print('This command was applied: sed -i "s/{}/{}/g" {}'.format(oldtext,newtext,file))
if you want to see results on the file directly apply: "type" for windows/ "cat" for linux:
####FOR WINDOWS:
os.popen("type " + file).read()
####FOR LINUX:
os.popen("cat " + file).read()
I have done this:
#!/usr/bin/env python3
import fileinput
import os
Dir = input ("Source directory: ")
os.chdir(Dir)
Filelist = os.listdir()
print('File list: ',Filelist)
NomeFile = input ("Insert file name: ")
CarOr = input ("Text to search: ")
CarNew = input ("New text: ")
with fileinput.FileInput(NomeFile, inplace=True, backup='.bak') as file:
for line in file:
print(line.replace(CarOr, CarNew), end='')
file.close ()
I modified Jayram Singh's post slightly in order to replace every instance of a '!' character to a number which I wanted to increment with each instance. Thought it might be helpful to someone who wanted to modify a character that occurred more than once per line and wanted to iterate. Hope that helps someone. PS- I'm very new at coding so apologies if my post is inappropriate in any way, but this worked for me.
f1 = open('file1.txt', 'r')
f2 = open('file2.txt', 'w')
n = 1
# if word=='!'replace w/ [n] & increment n; else append same word to
# file2
for line in f1:
for word in line:
if word == '!':
f2.write(word.replace('!', f'[{n}]'))
n += 1
else:
f2.write(word)
f1.close()
f2.close()
def word_replace(filename,old,new):
c=0
with open(filename,'r+',encoding ='utf-8') as f:
a=f.read()
b=a.split()
for i in range(0,len(b)):
if b[i]==old:
c=c+1
old=old.center(len(old)+2)
new=new.center(len(new)+2)
d=a.replace(old,new,c)
f.truncate(0)
f.seek(0)
f.write(d)
print('All words have been replaced!!!')
I have worked this out as an exercise of a course: open file, find and replace string and write to a new file.
class Letter:
def __init__(self):
with open("./Input/Names/invited_names.txt", "r") as file:
# read the list of names
list_names = [line.rstrip() for line in file]
with open("./Input/Letters/starting_letter.docx", "r") as f:
# read letter
file_source = f.read()
for name in list_names:
with open(f"./Output/ReadyToSend/LetterTo{name}.docx", "w") as f:
# replace [name] with name of the list in the file
replace_string = file_source.replace('[name]', name)
# write to a new file
f.write(replace_string)
brief = Letter()
Like so:
def find_and_replace(file, word, replacement):
with open(file, 'r+') as f:
text = f.read()
f.write(text.replace(word, replacement))
def findReplace(find, replace):
import os
src = os.path.join(os.getcwd(), os.pardir)
for path, dirs, files in os.walk(os.path.abspath(src)):
for name in files:
if name.endswith('.py'):
filepath = os.path.join(path, name)
with open(filepath) as f:
s = f.read()
s = s.replace(find, replace)
with open(filepath, "w") as f:
f.write(s)

Categories