Macro Complex instructions.



  • Well. I don’t know how to explain it so I will give the example right away:
    I have 2 Files
    File1 is a list:
    aaa
    bbb
    ccc
    ddd
    etc…
    And File2: all X are the same value
    Blue Box xxx
    It contains grapes and xxx
    Red Box xxx
    It contains tomatoes and xxx
    Green Box xxx
    It contains oranges and xxx
    Yellow Box xxx
    It contains lemons and xxx
    etc.

    I want is so macro can take from File1 and replace the first two xxx with aaa the 2nd two xxx with bbb and so on .

    How do I do that?



  • You could use a scripting language, like PythonScript. The general procedure would be akin to

    1. Open both File1 and File2.

    2. RClick on the File2 tab, and Move to Other View

    3. Run a PythonScript that does something like the following (not valid PythonScript… this just gives an outline in pseudocode.)

       // editor1 is the PythonScript object instance for the first (left or top) document window in NPP
       // editor2 is the instance for the second (right or bottom) document window
       for( lineNumber = 1 to editor1.getLineCount() )
           // grab the nth line from File1
           editor1.gotoLine(lineNumber)
           newValue = editor1.getCurLine()
           for ( time = 1 to 2 )
               // look for the first occurrence of 'xxx'
               position = editor2.findText( flags, 0, end, "xxx")      // Look in the PythonScript documentation
               //      for Editor Object > Scintilla Methods:
               //      I would need to study .findText() and the associated SCI_FINDTEXT more
               //      to figure out the right values for flags, and then search thru to find
               //      the right command for finding the end-location of editor2
               editor2.????(position, position+3)                      // select the text from "position" to "position+3" or whatever length of "xxx" is
               editor2.replaceSel(newValue)                            // replace the selected "xxx" with the newValue
      

    Sorry, I’m not a Python/PythonScript expert, and didn’t have much time this morning, otherwise I could have researched a bit more and tried to get valid/running code. Hopefully, this outline will spark a PythonScript guru (@Claudia-Frank , hint, hint) could turn this pseudocode into a valid PythonScript in a few minutes.

    (edit: added the for time=1 to 2 loop, because I forgot you wanted to replace two instances of each “xxx” with a given newValue)



  • @Annas-Taher

    Thx to Peter :-), I already have the logic to follow - should be straightforward.
    When back home I will build something but in the meantime you need to install
    the python script plugin (preferable use the msi) to make it work. And you have to use the 32bit version of notepad++
    as there is no python script plugin for 64 bit available yet.

    Cheers
    Claudia



  • Actually, it was pestering me so much I couldn’t think about anything else…

    This appears to do what @Annas-Taher described:

    # editor1 is the PythonScript object instance for the first (left or top) document window in NPP
    # editor2 is the instance for the second (right or bottom) document window
    
    for lineNumber in range(0, editor1.getLineCount() ):
        # grab the nth line from File1 (exclude newline)
        editor1.gotoLine(lineNumber)
        newValue = editor1.getCurLine().rstrip()
        console.write("editor1: #" + str(lineNumber) + " = \"" + newValue + "\"\n")
    
        editor2.documentEnd()               # go to the last position
        end2 = editor2.getCurrentPos()      # record the position
        console.write("editor2.end = " + str(end2)+"\n")
        editor2.documentStart()             # back to the beginning
        start2 = editor2.getCurrentPos()    # record the position
        console.write("editor2.start = " + str(start2)+"\n")
    
        # want to replace two "xxx" entries in File2 with each line from File1
        for time in range(1, 2):
    
            # look for the first occurrence of 'xxx', starting at start2 and ending at end2
            #  position is a tuple with the start and end locations of the match
            position = editor2.findText( FINDOPTION.MATCHCASE, start2, end2, "xxx")
            console.write("editor2: findText @ " + str(position[0]) + ":" + str(position[1]) + "\n")
    
            # select the "xxx"
            editor2.setSelectionStart(position[0])
            editor2.setSelectionEnd(position[1])
    
            # replace the selection with newValue
            editor2.replaceSel(newValue)
    
            # the cursor is now at the end of the replaced value, and we want to
            start2 = editor2.getCurrentPos()
            console.write("Start2: " + str(start2)+"\n")


  • @PeterJones

    So you gave me a job and fired me instantly :-D
    To quote Meat Loaf: “Is this the way to treat an employee (well he said “an expensive guitar”)” :-D

    Cheers
    Claudia



  • Well, there is a bug in the code: The nested loop isn’t working, and it’s just replacing one of each, rather than two xxx with each line from File1. So whichever of us finds the Round Tuit to debug the code first will get credit for final solution. :-)



  • @Annas-Taher
    @PeterJones

    from your description I would solve it like this

    editor1_list = editor1.getText().split()
    string_to_be_replaced = 'xxx'
    line_counter_editor2 = 0
    
    editor.beginUndoAction()
    for i in editor1_list:
        editor2.replaceLine(line_counter_editor2, editor2.getLine(line_counter_editor2).replace(string_to_be_replaced, i).rstrip())
        editor2.replaceLine(line_counter_editor2+1, editor2.getLine(line_counter_editor2+1).replace(string_to_be_replaced, i).rstrip())
        line_counter_editor2 += 2
    editor.endUndoAction()
    

    If the code doesn’t explain itself, let me know.

    Cheers
    Claudia



  • Hello @annas-taher, and All,

    Surely, Claudia and Peter, your Python scripts should give nice results. I just imagined … a regex S/R equivalent method :-))

    Annas, my method, below, will work, assuming two facts :

    • The expression xxx ends all the lines of File2

    • The number of lines of the list, in File1, is, exactly, half the number of lines of File2


    If so, first, merge the File1 contents, right after the File2 contents, as below, and save these contents as File3 :

    Blue Box xxx
    It contains grapes and xxx
    Red Box xxx
    It contains tomatoes and xxx
    Green Box xxx
    It contains oranges and xxx
    Yellow Box xxx
    It contains lemons and xxx
    aaa
    bbb
    ccc
    ddd
    

    Then, in File3, with a first regex S/R, we join two consecutive lines, ending with the xxx expression

    SEARCH (?-s)^(.+xxx)\R(.+xxx)

    REPLACE \1\2

    OPTIONS Wrap Around and Regular expression checked

    ACTION Click on the Replace All button

    You should obtain the text, below :

    Blue Box xxxIt contains grapes and xxx
    Red Box xxxIt contains tomatoes and xxx
    Green Box xxxIt contains oranges and xxx
    Yellow Box xxxIt contains lemons and xxx
    aaa
    bbb
    ccc
    ddd
    

    Notes :

    • As usual, the (?-s) modifier, ensures that the dot special character will match standard characters, only

    • The ^ assertion represents the position beginning of line, which must be verified

    • The two syntaxes (.+xxx) catch the contents of two consecutive lines, ending with xxx, and stored, successively, in group1 and group 2, due to each pair of parentheses

    • The \R form represents the line-break characters between these two lines

    • In replacement, we rewrite the contents of the two lines, \1\2, except for the line break


    Well. now, note that after the first line, you have to cross 3 complete lines to get the aaa first line of your list

    Therefore, we’ll use the second and last regex S/R, below :

    SEARCH (?-s)^(.+)xxx(.+)xxx\R(?=(?:.+\R){3}(.+\R))

    REPLACE \1\3\2\3

    OPTIONS Wrap Around and Regular expression checked

    ACTION Click on the Replace All button

    => Your File3 contents should be as below :

    Blue Box aaa
    It contains grapes and aaa
    Red Box bbb
    It contains tomatoes and bbb
    Green Box ccc
    It contains oranges and ccc
    Yellow Box ddd
    It contains lemons and ddd
    aaa
    bbb
    ccc
    ddd
    

    Notes :

    • This time, group 1 and group 2, (.+), contain the totality of the two consecutive lines, apart from the xxx expression

    • So, the part ^(.+)xxx(.+)xxx\R matches each complete line, with its line-break

    • But, ONLY IF, further on, the positive look-ahead (?=(?:.+\R){3}(.+\R)), ( where it looks for 3 complete lines, with its line-break character(s), in a non-capturing group, (?:.+\R){3}, followed with an other complete line (.+\R) ) , is verified

    • Note that this condition is always true, but, thanks to this syntax, we can store any line of the list aaa, bbb,… as group 3

    • In replacement, we simply, rewrite groups 1 and 2, replacing the old expression xxx by \3 which represents any value of the list aaa, bbb and so on…, with its line breaks, to get the initial form of the text


    Finally, just get rid of the list aaa......ddd, at the end of File3 ( Ctrl + Shift + End and Del ! )

    Of course, for n lines, between the first one and the aaa line, simply change the search regex as :

    (?-s)^(.+?)xxx(.+?)xxx\R(?=(?:.+\R){n}(.+\R)) , with the appropriate integer n

    Best Regards,

    guy038



  • For completeness, I eventually found the bug in mine: I was misusing range(start, end) – I thought it included end when iterating over the range, but it only uses the values less than end.

    The following is my code, with the bug fixed (and some of my debug prints left in) that I think now does what was requested… though @Claudia-Frank did it much more succinctly… and the magic of @guy038 regex ability is virtually limitless. :-)

    # editor1 is the PythonScript object instance for the first (left or top) document window in NPP
    # editor2 is the instance for the second (right or bottom) document window
    
    # Python's range(start, stop) operator will keep going while the index variable is LESS THAN stop, so it will never use stop: https://docs.python.org/2/library/functions.html#range
    for lineNumber in range(0, editor1.getLineCount() ):
        # grab the nth line from File1 (exclude newline)
        editor1.gotoLine(lineNumber)
        newValue = editor1.getCurLine().rstrip()
        console.write("editor1: #" + str(lineNumber) + " = \"" + newValue + "\"\n")
    
        editor2.documentEnd()               # go to the last position
        end2 = editor2.getCurrentPos()      # record the position
        console.write("editor2.end = " + str(end2)+"\n")
        editor2.documentStart()             # back to the beginning
        start2 = editor2.getCurrentPos()    # record the position
        console.write("editor2.start = " + str(start2)+"\n")
    
        # want to replace two "xxx" entries in File2 with each line from File1
        for time in range(0, 2):
            console.write("time# " + str(time) + "!!!\n")
    
            # look for the first occurrence of 'xxx', starting at start2 and ending at end2
            #  position is a tuple with the start and end locations of the match
            position = editor2.findText( FINDOPTION.MATCHCASE, start2, end2, "xxx")
            if position is None:
                console.write("editor2.position is NONE, so skipping...\n")
                break                   # don't try to replace
    
            console.write("editor2: findText @ " + str(position[0]) + ":" + str(position[1]) + "\n")
    
            # select the "xxx"
            editor2.setSelectionStart(position[0])
            editor2.setSelectionEnd(position[1])
    
            # replace the selection with newValue
            editor2.replaceSel(newValue)
    
            # the cursor is now at the end of the replaced value, and we want to
            start2 = editor2.getCurrentPos()
            console.write("Start2: " + str(start2)+"\n")
    
        console.write("next source line...\n")

Log in to reply