Find and replace strings with python

python-big

The following code was designed for situation where you have a folder with about 50 subfolders and a script file in each subfolder. With a bit of changes code can be adjusted to similar situations and effectively used to save time. If you haven’t got your python environment setup on windows already, here’s a tutorial on how to quickly setup python.

import fileinput
import re
from tempfile import mkstemp
from shutil import move
from os import remove, close
import os

def main():
    folders = getFolderNames(r'C:\main_folder');

    for folder in xrange(0, len(folders)):
        files = getFileNames(r'C:\main_folder\%s' %folders[folder], '.py');

        for file in xrange(0, len(files)):
            findAndReplace(r'C:\main_folder\%s' %folders[folder], files[file]);

if __name__ == '__main__':
    main()

The code won’t work without getFolderNames, getFileNames, replace and findAndReplace functions which are explained below. In order for this script to work properly add necessary functions after def main() function or download find_and_replace.py from pythonicways GitHub page.

Explanation:

def getFolderNames(root):
    folders = [];
    for item in os.listdir(root):
        if os.path.isdir(os.path.join(root, item)):
            folders.append(item);
    return folders

getFolderNames does exactly that. It returns subfolder names of root folder. All folder names are appended to folders list.

def getFileNames(folder, extension):
    names = [];
    for file_name in os.listdir(folder):
        if file_name.endswith(extension):
            names.append(file_name)
    return names

This function returns file name. You can indicate specific file extension in order to see only, for example, python files.

def replace(file_path, pattern, subst):
    fh, abs_path = mkstemp()
    with open(abs_path,'w') as new_file:
        with open(file_path) as old_file:
            for line in old_file:
                new_file.write(line.replace(pattern, subst))
    close(fh)
    remove(file_path)
    move(abs_path, file_path)

replace function replaces specific pattern with the new pattern (subst). In order to achieve this seamlessly, we have to create a new file, re-write each line from the old one, but this time replacing specific text with the new one.

def findAndReplace(path, filename):
    file_path = path + '\\' + filename
    match_list = [];
    repl_list = [];
    with open(file_path, 'r+') as f:
        for line in f:
            for match in re.finditer('(type\(waitForObject\(.*?(.+?)\)\, )(.*?(.+?))\)', line, re.S):
                match_text = match.group();
                obj = match.group(2);
                input_txt = match.group(3);
                repl_text = 'typeText('+ obj +', '+ input_txt +')'
                match_list.append(match_text)
                repl_list.append(repl_text)
    print '    '
    print 'In file path: %s' %file_path
    for item in xrange(0, len(match_list)):
        print '%s     replaced with     %s' %(match_list[item], repl_list[item])
        replace(file_path, match_list[item], repl_list[item])

findAndReplace is the main function in this script. The path and filename variables points to the file location in which you want to change something. for match in re.finditer(‘(type\(waitForObject\(.*?(.+?)\)\, )(.*?(.+?))\)’, line, re.S) matches specific text with variables in them. Original text: type(waitForObject(object_variable), text_to_type). Using above lines of code you are able to match variable object and text.

It is a bit tricky to save object variable and input text, in order to achieve this you have to use regex. Good thing that re.finditer offers grouping, which means that if you create your regex correctly you can divide found text in parts. In this example we have divided it in three parts. match.group() match the whole found text, match.group(2) match variable object and match.group(3) match input text. This was necessary for the next step repl_text = ‘typeText(‘+ obj +’, ‘+ input_txt +’)’ which uses saved string values (obj, input_text) in order to create the replacement text. Once replacement text is created, it’s added to repl_list.

Finally, we use match_list and repl_list in combination with for loop to replace one string value with another. If you simply want to replace a string with another string, see below example.

By the way, RegExr is a great website where you can learn to match complicated texts with regex even if you haven’t used it before.

def findAndReplace2(path, filename):
    file_path = path + '\\' + filename
    match_list = [];
    repl_list = [];
    with open(file_path, 'r+') as f:
        for line in f:
            for match in re.finditer('syncingStatus', line, re.S):
                match_text = match.group();
                repl_text = 'findSyncingStatus'
                match_list.append(match_text)
                repl_list.append(repl_text)
    print '    '
    print 'In file path: %s'; %file_path
    for item in xrange(0, len(match_list)):
        print '%s     replaced with     %s' %(match_list[item], repl_list[item])
        replace(file_path, match_list[item], repl_list[item])

You can use findAndReplace2 function to simply replace one text with another text. In this example syncingStatus is replaced with findSyncingStatus.

Find file location with python

Usually when you work on a bigger project, which involves many script files it’s hard to quickly find which script files contain specific function or text. Here’s a very simple modification to the original findAndReplace fuction which will help you with that.

def findFileLocation(path, filename, regex):
    file_path = path + "\\" + filename
    with open(file_path, "r+") as f:
        for line in f:     
            for match in re.finditer(regex, line, re.S):
                print "In file path: %s" %file_path
                

You can assign special regular expression string or simple text to regex variable and this function will return full path to file that contains regex string.

Searching for subfolder names and then going through each subfolder and it’s containing python script file to find regex text findGreenIcon( .

def main():
    folders = getFolderNames(r"C:\main_folder");
 
    for folder in xrange(0, len(folders)):
        files = getFileNames(r"C:\main_folder\%s" %folders[folder], ".py");
         
        for file in xrange(0, len(files)):
            findFileLocation(r"C:\main_folder\%s" %folders[folder], files[file], 'findGreenIcon\(');
              

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s