Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Search and Replace (dangerous)

dave1707dave1707 Mod
edited July 2013 in Code Sharing Posts: 7,913

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.

    

Comments

  • Posts: 391

    @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.

  • dave1707dave1707 Mod
    Posts: 7,913

    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.

  • Posts: 1,595

    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..

  • edited July 2013 Posts: 391

    @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.

  • dave1707dave1707 Mod
    Posts: 7,913

    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.

  • BriarfoxBriarfox Mod
    Posts: 1,542

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

  • dave1707dave1707 Mod
    edited July 2013 Posts: 7,913

    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\n 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.."\nWITH    "..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,"\n"," ")     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

        

  • dave1707dave1707 Mod
    edited July 2013 Posts: 7,913

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

    Made more changes.

  • BriarfoxBriarfox Mod
    Posts: 1,542

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

  • Jmv38Jmv38 Mod
    Posts: 3,295

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

  • Posts: 2,820

    Sweet! Thanks a lot.

  • dave1707dave1707 Mod
    Posts: 7,913

    @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.

  • dave1707dave1707 Mod
    Posts: 7,913

    @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.

  • Posts: 391

    @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?

  • dave1707dave1707 Mod
    edited July 2013 Posts: 7,913

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

  • Jmv38Jmv38 Mod
    Posts: 3,295

    @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.

  • dave1707dave1707 Mod
    Posts: 7,913

    @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.

  • BriarfoxBriarfox Mod
    Posts: 1,542

    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
    
    
  • dave1707dave1707 Mod
    Posts: 7,913

    @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.

  • dave1707dave1707 Mod
    Posts: 7,913

    @Briarfox Thank for the changes for landscape/portrait. I added that to the code above and removed the original code at the top of this discussion.

  • BriarfoxBriarfox Mod
    Posts: 1,542

    Thanks dave1707! I just prefer to cut and paste if a change has been made. I tend to forget that I modify code, paste over it and can't figure out why something isn't quite right :P

  • dave1707dave1707 Mod
    Posts: 7,913

    Here is an updated version of the program. I added several minor changes, but the major change is to hold all of the updates until the end and then ask if you want to discard or update the changes. I also print the project:tabs that were updates. I suggest trying this on a test program until you're OK with the changes that were made.


    function setup()     parameter.text("project","")     parameter.text("findStr","")     parameter.text("replStr","")     parameter.action("Start Search / Replace",startSearch)         setup1() end function setup1()      showKeyboard()       rectMode(CENTER)     output.clear()     projTable={}     dataTable={}     tableOffset=0     updateTabs=false     searchProject=false     getNextTab=true     replaced=false     found=false     textChanged=false     next=0     str2='Enter project, findStr and replStr\n then press   "Start Search / Replace"'     str3=""     hFind=""     hRepl=""     func=process end function startSearch()     if project == "" then         str2="Project name missing"     elseif findStr =="" or replStr=="" then         str2="findStr or replStr is empty"     else         setup1()         tab=listProjectTabs(project)         if #tab>0 then             searchProject=true             hideKeyboard()             hFind=findStr             hRepl=replStr         else             str2="Project not found"         end     end end function draw()     background(40,40,50)     func() end function process()     if hFind~="" or hRepl~="" then         if hFind~=findStr or hRepl~=replStr then             setup1()         end     end     font("CourierNewPS-BoldItalicMT")     noFill()     strokeWidth(2)     rect(WIDTH/2,550,460,100)     fill(255)      text(str2,WIDTH/2,550)     text(str3,WIDTH/2,530)     if searchProject then         if getNextTab then             nextTab()         end         if searchProject then             text("PROJECT:TAB   "..project..":"..tab[next],WIDTH/2,700)             text("REPLACE".."   "..findStr.."\nWITH    "..replStr,WIDTH/2,650)             find()         end     end end    function nextTab()     next=next+1     getNextTab=false     if next > #tab then         searchProject=false         str2=""         str3=""         if textChanged then             updateTabs=true             func=selectChanges         elseif not found then             str2=findStr.."    not found "         else             str2="You skipped all matches, no updates needed."         end     else         projectTab=string.format("%s:%s",project,tab[next])         data=readProjectTab(projectTab)         start=1     end end         function find()     str2=""     a,b=string.find(data,findStr,start,true)     if a==nil then         if replaced then             tableOffset=tableOffset+1             projTable[tableOffset]=projectTab             dataTable[tableOffset]=data         end         getNextTab=true         replaced=false         return     end     found=true     a1=a-10     b1=b+10     a2=10     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,"\n"," ")     str3=string.rep(" ",a2)     str3=str3..string.rep("*",string.len(findStr))     str3=str3..string.rep(" ",b2)     skipReplace() end function skipReplace()       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 replaceOption()     replaced=true     textChanged=true     data=string.format("%s%s%s",string.sub(data,1,a-1),     replStr,string.sub(data,b+1,-1))     start=a+string.len(replStr)     func=process end function skipOption()     start=a+1     func=process end function selectChanges()     fill(255)     rect(WIDTH/2-125,700,200,50)     rect(WIDTH/2+125,700,200,50)     fill(0,255,0)     text("DISCARD CHANGES",WIDTH/2-125,700)      fill(255,0,0)     text("UPDATE CHANGES",WIDTH/2+125,700) end function completeOption()     str2="Update Complete"     for z=1,#projTable do         saveProjectTab(projTable[z],dataTable[z])         print("Updated  "..projTable[z])     end     clear() end function discardOption()     str2="Updates discarded"     clear() end function clear()     findStr=""     replStr=""     hFind=""     hRepl=""     func=process end          function touched(t)     if updateTabs then         if t.state==BEGAN and t.y>675 and t.y<725 then             if t.x>WIDTH/2-200 and t.x<WIDTH/2-50 then                 func=discardOption             end             if t.x>WIDTH/2+50 and t.x<WIDTH/2+200 then                 func=completeOption             end         end      end     if searchProject then         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                 func=skipOption             end             if t.x>WIDTH/2+75 and t.x<WIDTH/2+175 then                 func=replaceOption             end         end      end end
  • Posts: 372

    Just Discovered it today, while using AirCode if you Select something then press Ctrl+alt+left/Right arrow key then it selects all the similar matches. It could be useful to do a mass replace. But ofcourse if you have a vraible called "ion" and then if you try this method it will select the "ion" in "function" too. So best use it for uniquely spelled variables

Sign In or Register to comment.