Replace In files based on a condition



  • Hi,

    I want to replace a string in a large number of files only if that file contains another string e.g replace “abc” with “def” only if the file contains “<123>”

    Is there any way of doing this?

    Regards



  • @Graham-White

    simple answer yes.
    BUT without knowing how such data could look like it is hard to say
    what needs to be done.



  • Hi,

    I have a heap of XML files and I want to replace <LockingStrategy val=“I”/> with <LockingStrategy val=“O”/> in all files that also contain TaskType val=“O”/>

    Regards



  • @Graham-White

    Can you provide such an xml example?
    The reason why I’m asking is to find out whether
    TaskType val=“O”/> is on the same place always or if it
    can be on different places but within the main tag etc…
    Basically, is there some kind of data layout we can rely on.
    like TaskType val=“O”/> is always five lines before or after X
    or within the same main tag but can occur after and before …



  • @Eko-palypse :

    My thought would be, based on his description of “file also contains XXX”, to do an search for ( MATCH followed by lookahead(.*XXX) OR lookahead(XXX.*) followed by MATCH ) – but I don’t have the time right now to convert that to a regular expression and verify it works

    Of course, really, this should be written in a scripting language, and run from a command line rather than from inside Notepad++… but we always seem to be willing to jump through the wonderful hoops that regex provide to make the customer happy. :-)



  • @PeterJones said:

    but we always seem to be willing to jump through the wonderful hoops that regex provide to make the customer happy. :-)

    I guess this will end in something like this :-)
    But you are right, with a script it would be something like

    for file in directory
        open(file)
            if condition in content
                search_replace
    


  • Hi,

    I don’t have a data layout. The <TaskType… and the <LockingStra…. are between the tag <Task MainProgram=“N”> and </Task> there can be multiple <Task> </Task> groupings in the xml’s. There is no consistency in the number of lines between the tags. Does this help?

    I can send a you an example of a couple of the files if that helps. Send me your email address if you require these.

    Regards



  • @PeterJones , @Eko-palypse @Graham-White
    I have an idea to do this in 2 steps. The first would be to ‘touch’ each file with a regex that literally writes back everything to the file ONLY if the required text is present in the file (not changing anything), but that allows the datetime stamp of the file to be updated.

    Then the second step will ONLY work on those files to change the ‘other’ text which must exist as the datetime stamp was updated in the previous step. This allows for the ‘filter’ text to be anywhere in the file, and won’t require any consideration to the lookahead’s possible failure on large files.

    Terry



  • @Terry-R

    I understand what you are saying but I don’t know how you want to achieve that.
    With regex or script or find replace dialog and replace in all opened files?



  • Using the ‘Find in Files’ option, I did a test with a small html file that included the text OTHER_2. Another html file did NOT contain this text.
    My regex was
    Find What(?s)(.+?)(OTHER_2)(.+?)(.)
    Replace With:\1\2\3\4

    I should say that the last '.` was because I was considering another option, this regex could be a bit shorter but I was only testing.
    I listed the folder and filter as *.html (so it would only interact with 2 files). The one with the text had it’s datetime stamp updated, the other did NOT.

    Then for the second regex, you could select those ‘updated’ files and drop them onto NPP and use the regex on all open files and then save them all.

    I think due to the uncertainty of where the 2 texts would be in relation to each other (1 before 2 or 2 before 1) means it makes it complicated to cater for with 1 regex. Together with the lookahead bug I think it’s likely to come unstuck. Maybe 1 regex could do it, but as @PeterJones said “willing to jump through the wonderful hoops that regex”.

    Sometimes although regex provides lots of power at our fingertips, maybe sometimes simple (and possibly more steps) means the OP can more easily understand it, and more importantly has the ability to ‘update’ it over time.

    Terry



  • ah, I see my approach is slightly different.

    1. Start a new npp without any files open
    2. Using also find in files dialog and search for the condition
    3. right-click in find result window and click open all
    4. Using find and replace with option Replace All in All Opened Documents
    5. Done - I hope.


  • Hey thanks @Eko-palypse
    I never realised that option existed (yeah I know it was in front on me ALL this time!). I must admit I was somewhat concerned that I was having to ‘touch’ files, although that was tempered by the fact I was ONLY ‘touching’ those that would be later edited anyways.

    There was an OP a while back that when presented with something like this was adamant they did NOT want the files’ datetime stamp altered unduly.

    Terry



  • What?? They want to change files without changing its timestamp ?
    Hmm … doesn’t sound healthy … I don’t say they want do bad stuff but
    resetting timestamp back to what it was … :-)



  • If you are willing to run the search/replace multiple times, if you have files like

    <LockingStrategy val="I"/>
    <SomethingElse/>
    <LockingStrategy val="I"/>
    <SomethingElse/>
    <TaskType val="O"/>
    <LockingStrategy val="I"/>
    <SomethingElse/>
    <LockingStrategy val="I"/>
    <SomethingElse/>
    

    The the following search+replace (Find in Files) will get all the matches before the condition, and at least one of the matches after the condition. However, if there is more than one after the condition, you will have to run the replace in files more than once.

    With a bit more tweaking, I am sure it could be made to work all in one go, but I haven’t been able to figure it out yet.

    • Find = (?s)(<LockingStrategy val="I"/>(?=.*TaskType val="O"/>)|(?=TaskType val="O"/>).*\K<LockingStrategy val="I"/>) or (?s)(<LockingStrategy val="I"/>(?=.*TaskType val="O"/>)|(?=TaskType val="O"/>).*?\K<LockingStrategy val="I"/>)
      • the first will find the LAST match after the condition as the post-condition to be replaced
      • the second will find the FIRST match after the condition as the post-condition to be replaced
      • the match-before-condition will find all of them.
    • Replace = <LockingStrategy val="O"/>
    • Search Mode = Regular Expression

    I technically only tried this in one file at a time, but in theory, everything that works in one file will work the same in multiple files. I did verify it worked if there were no matches after the condition, and it “works” (replaces one at a time) if all the matches are after the condition.

    I’ve got another idea, but not sure if I’ll have time to test it tonight (and will have forgotten it by tomorrow), so I’ll post for now.



  • Yeah, the second idea isn’t going to work as I had it.

    What I am looking for is a way (similar to \K) to reset the beginning of the match back to the beginning of the TaskType val="O"/> after the replacement has occurred, so that it’s searching from that same spot again to find the next match. But I don’t know how to do that.

    For now, the best I have is to run the replace-in-files multiple times until they’re all gone. Not ideal, I know, especially if there might be thousands of matches after the conditional. Which is why I’m still an advocate for scripting this, not regexing it.



  • Hello, @graham-white and All,

    To be as accurate as possible, I just think that the best would be to get one or some samples of your XML files, first ;-))

    So, if you don’t mind, and if your data are not personal nor confidential, simply attach some examples to your mail to :

    tguy.038@gmail.com

    See you later,

    Best Regards,

    guy038



  • @Eko-palypse I am unsure what you mean in step 2 by “Using also” can you please elaborate

    Regards



  • Don’t be confused by my new name - verification for my account via google isn’t possible at the moment
    so I had to register an account at github. phew …

    What I meant is,
    You start a npp session without any documents loaded or use an
    existing npp session and close all documents.

    Then use the standard find in files dialog and search for the condition
    As a result of this search you should get a new find result windows.

    Within the new result window you can right-click and use Open All.
    Now you should have all files open which do have the condition in it.

    Last step would be using the normal find/replace dialog and define
    your find and replace arguments and use the button Replace All in All Opened Documents

    This should result in what you want to have.



  • @Ekopalypse

    did the google login symbol disappear as an option when you tried to login again, or was there a problem after clicking on the google g icon ?

    if the google login just disappeared as an option: make sure you are logged in at google.com, logoff your git account at this community, disable any adblocker or js-blocker and reload the community login page.



  • @Meta-Chuh

    no, the button is still there.
    When I tried to log in, I was allowed to
    enter the name and the password, after that I was
    asked what my cell phone number was, since I could not become verified.
    As I couldn’t provide the first possibility nor the second
    for my account verification, because initially not specified at all,
    I get now with every attempt the hint that google could not verify me.

    I even get this as confirmation in my gmail inbox,
    where I can log in without any problems.
    As a hint I get that someone tried to log on from another computer,
    right around the time I’m tried to log on here.

    Strange…


Log in to reply