Search and Replace (dangerous)

Here is a program I put together that will allow you to do a search and replace on a project. It will do a search thru all of the tabs. You have to put the project name, find string, and the replace string in the program before running. It will stop each time it finds what you’re searching for and shows you 10 characters before and 10 characters after the string you are replacing. You have the option to SKIP or REPLACE that string. I haven’t found a good way to show the string being replaced, but the 10 character before and after works for now. You may see multiple lines if there are newlines characters that’s being shown. I suggest making copies of any project you run this on until you are sure how it works. I am NOT responsible for any project you mess up by using this, so use at your own risk. You can mess things up real fast using this.


Original code deleted by author.

Use the updated code below.

@dave1707, just tested this and it works like a charm! I got a quick suggestion that may be fairly simple to implement. Could you have it store the strings you decide to replace into a table and when it finishes, save that locally for a quick undo? Being able to do a single undo would probably save someone from a heart attack if they do end up messing up their program.

Just flipping findStr and replStr should do the same thing for undo. Doing an undo could be just as dangerous if you don’t watch what’s happening. Making a copy before running the program could save a lot of headaches.

Have the program store and original copy? It works good but codea could do with a function to get a list of all the projects to make a simple select box and I can think of a few things I could use it for aswell…

@Luatee, yeah storing the whole original project would be an even simpler task. Then just have it replace the full project with the original. I think I’ll add this into the code since I plan on using this very often, at least until Codea comes out with a search and replace.

Edit: also going to make the search string and replace string parameters along with a nice action parameter to execute it.

saveProjectTab(project:tab) doesn’t work unless the project already exists. Writing the program to Dropbox would work using the program I wrote “project backup” that I posted July 17th. The program can be copied from Dropbox and pasted back to the original project. I didn’t get too creative with this program since I wasn’t sure if it would be used that much.

I like it and will use it! No more textastic needed!

Here’s my original program with parameters added. I’ll let someone else add the backups.

EDIT: Can someone come up with a better way of showing the string being replaced.

EDIT: Added a line of code in the function replace() to replace any newlines character with a space so the line being shown won’t be on multiple lines. That might be easier to determine if the string needs to be replaced or not.

EDIT: I replaced the previous listing here with this one. I changed the code so that I show asterisks below the string that will be replaced. I think that’s easier to see what would be replaced.

EDIT: I made corrections for the asterisks if the findStr was close to the beginning or end of the program.


function setup()
    parameter.text("project","")
    parameter.text("findStr","")
    parameter.text("replStr","")
    parameter.action("Start Search / Replace",sr)
    setup1()
end

function setup1()       
    projectDone=true
    getNextTab=true
    replaced=false
    found=false
    next=0
    rep=0
    str2=""
    str3=""
    rectMode(CENTER)
end

function sr()
    if project == "" then
        str2="Project name missing"
    elseif findStr =="" or replStr=="" then
        str2="Find string or Replace string\
 is empty"
    else
        setup1()
        tab=listProjectTabs(project)
        if #tab>0 then
            projectDone=false
        else
            str2="Project not found"
        end
    end
end

function draw()
    background(40,40,50)
    fill(255)
    if not projectDone then
        if getNextTab then
            nextTab()
        end
        if not projectDone then
            find(st)
            text("PROJECT:TAB   "..project..":"..tab[next],WIDTH/2,700)
            text("REPLACE".."   "..findStr.."\
WITH    "..replStr,WIDTH/2,650)
        end
    end
    font("Courier-BoldOblique")
    noFill()
    strokeWidth(2)
    rect(WIDTH/2,550,460,100)
    fill(255) 
    text(str2,WIDTH/2,550)
    text(str3,WIDTH/2,530)
    rect(WIDTH/2-125,400,100,50)
    rect(WIDTH/2 +125,400,100,50)
    fill(0,255,0)
    text("SKIP",WIDTH/2 - 125,400) 
    fill(255,0,0)
    text("REPLACE",WIDTH/2+125,400)    
end

function nextTab()
    next=next+1
    getNextTab=false
    if next > #tab then
        projectDone=true
        str2="Find / Replace Complete"
        str3=""
        if not found then
            str2=findStr.."    not found "
        end
    else
        projectTab=string.format("%s:%s",project,tab[next])
        data=readProjectTab(projectTab)
        st=1
        rep=0
        done=false
    end
end   
    
function find(s)
    str2=""
    a,b=string.find(data,findStr,s,true)
    if a==nil then
        done=true
        if replaced then
            saveProjectTab(projectTab,data)
        end
        getNextTab=true
        replaced=false
        return
    end
    replace(a,b)
    found=true
    if rep==2 then
        replaced=true
        data=string.format("%s%s%s",string.sub(data,1,a-1),
        replStr,string.sub(data,b+1,-1))
        st=a+string.len(replStr)
        rep=0
    elseif rep==1 then
        st=a+1
        rep=0
    end
end

function replace(a,b)
    local a1=a-10
    local b1=b+10
    local a2=10
    local b2=10
    if a1<1 then
        a1=1
        a2=a-1
    end
    if b1>string.len(data) then
        b1=string.len(data)
        b2=string.len(data)-b
    end
    str2=string.sub(data,a1,b1)
    str2=string.gsub(str2,"\
"," ")
    str3=string.rep(" ",a2)
    str3=str3..string.rep("*",string.len(findStr))
    str3=str3..string.rep(" ",b2)
end

function touched(t)
    if t.state==BEGAN and t.y>375 and t.y<425 then
        if t.x>WIDTH/2-175 and t.x<WIDTH/2-75 then
            rep=1
        end
        if t.x>WIDTH/2+75 and t.x<WIDTH/2+175 then
            rep=2
        end
    end    
end

Made updates to the above program. See EDIT: above.

Made more changes.

Works great, I just tweaked the buttons so they line up in landscape. Thanks.

Very nice.
I hit a bug: i tried to replace ‘–’ by ‘-- --’ just to test it but then it behaves strangely.

Sweet! Thanks a lot.

@Jmv38 I think there a certain characters that have a special meaning in string.find(), so they act different when used together. I haven’t tried them all to see what they do but some of them match any character.

@Jmv38 I added “true” to the string.find() line of code in the function find(). This forces a “plain” string.find and doesn’t consider any character as magic. Your search/replace for – now works like it should, and the other magic characters shouldn’t cause a problem either. Just don’t keep replacing – with – – or you’ll end up with – – – – – – – . I start the next search 1 character beyond the previous find, so I’ll find the – in the string just added. It’s up to the person doing the search/replace to know when to skip or replace the string.

@dave1707, wow you quickly improved upon this program. I’m loving the additions. I got a suggestion to help combat the issue you mention above.

Instead of having it go 1 character beyond the previous find, how about have it go (replacestr.length - searchstr.length) characters beyond the previous find so it also skips what it inserted?

@Slashin8r Thanks for the suggestion. Change complete in the above program. I just added the string.len of replStr. That works OK.

@Dave1707 thank for the changes. Seems to work perfectly now.
If you want to improve it a little bit, you could do the foolowing: add a ‘save changes now’ button: this way it is possible to stop the search/replace without losing previous changes or having to press ‘skip’ many times. Just a suggestion.

@Jmv38 Actually I had something like that already coded. I didn’t think that would be useable to make some changes but not continue thru the program to check if there were other changes. Also, the changes don’t take affect until the search is complete with the current tab. Depending on the amount of the code in the tab, you could make changes then manually exit the program and the changes won’t be saved. I don’t do a saveProjectTab() until I reach the end of the code in that tab. I don’t know if that’s a problem or a way to exit without saving the changes. Another thing I was thinking of was not saving anything until the end, then ask if the changes should be saved or not. That would be an easy addition, but I don’t know if it’s needed. Adding your suggestion to skip to the end wouldn’t be a problem either.

Any Chance you could add this into your code to support landscape orientation? I also found it handy too print out skipped or replaced so I could tell if I tapped the wrong button on accident, thus allowing me to exit and not save.

Also which post are you updating? The OP or the one after it?

In draw

    rect(WIDTH/2-125,400,100,50)
    rect(WIDTH/2 +125,400,100,50)
    fill(0,255,0)
    text("SKIP",WIDTH/2 - 125,400) 
    fill(255,0,0)
    text("REPLACE",WIDTH/2+125,400)

touch()

function touched(t)
    if t.state==BEGAN and t.y>375 and t.y<425 then
        if t.x>WIDTH/2-175 and t.x<WIDTH/2-75 then
            rep=1
            print("Skipped")
        end
        if t.x>WIDTH/2+75 and t.x<WIDTH/2+175 then
            rep=2
            print("Replaced")
        end
    end
end

@Briarfox I’ve been making changes to the last one. I probably should delete the first one just to save space. I’ll update the code to work in both landscape and portrait. As for the printing, I’ll leave that up to each person to add it or not, that’s an easy addition. I’m sure some coders are adding stuff for their own preference.