How to bookmark lines around a line containing a specific expression 'XXX' ?



  • Hi, All,

    From that issue created in August 2019 by @scott-sumner ( Scott, thanks for your many GitHub contributions ! )

    https://github.com/notepad-plus-plus/notepad-plus-plus/issues/6018

    and the commit :

    https://github.com/alberto-dev/notepad-plus-plus/commit/520678cf1bc20bf701bc130564463a40e2391cef

    We are, from now on, able to mark any non-empty line, involved in a multi-lines search ;-))

    Due to this nice improvement, my previous post, below, about multi-lines bookmarking is rather obsolete :-(

    https://notepad-plus-plus.org/community/topic/16701/how-to-mark-lines-above-marked-lines/8


    So, here is an updated version ;-))

    Notes :

    • First, you’re presently using the Notepad++ version 7.8 or above

    • I assume that you’re using the Edit > Mark... dialog :

      • The options Bookmark lines, Purge for each search and Wrap around are ticked

      • The Regular expression mode is selected

    • The search process is supposed to be sensitive to case, due to the (?-i) in-line modifier

    • To simplify, I assume that the lines, containing the XXX criterion, do not overlap with the lines around, which need bookmarking !


    Edited on 11-16-2019

    The end of this present post is rather obsolete and/or erroneous, as my updated regexes can, now, handle pure empty lines, too !

    So you should better to refer to the next post, below :

    https://community.notepad-plus-plus.org/post/48541


    • You certainly noticed that the marking feature does not bookmark empty lines. So, if your text contains empty lines, that you would like to bookmark, too, a possible work-around could be to use a dummy character, not used yet in your file and, temporarily, replace any true empty line with some of these dummy chars, using the following regex S/R :

      • SEARCH ^(?=\R)

      • REPLACE ### , if the # symbol is presently absent from your file contents

    After the red-marking and bookmarking operation, with an appropriate search regex :

    • In your original file, just perform an Edit > Undo operation ( or Ctrl + Z )

    • In the new tab, where you would had copied all the bookmarked lines ( Search > Bookmark > Copy Bookmarked Lines ) run this simple regex S/R :

      • SEARCH ^###

      • REPLACE Leave EMPTY


    This first table, below, shows how to mark consecutive lines, around a line containing a specific expression XXX. Almost obvious ;-))

        •======================================================•===========•==========•===========•
        |  REGULAR expression to mark Line X, containing 'XXX' | Nth lines |  Line X  | Mth lines |
        |  and Nth lines BEFORE and/or Mth lines AFTER line X  |   BEFORE  |          |   AFTER   |
        •======================================================•===========•==========•===========•
        | (?-is)^(.+\R){N}(?=.*XXX)                            |    YES    |     NO   |      NO   |
        •------------------------------------------------------•-----------•----------•-----------•
        | (?-is)^.*XXX.*\R\K(.+\R){M}                          |     NO    |     NO   |     YES   |
        •------------------------------------------------------•-----------•----------•-----------•
        | (?-is)^(.+\R){N}(?=.*XXX)|^.*XXX.*\R\K(.+\R){M}      |    YES    |     NO   |     YES   |
        •------------------------------------------------------•-----------•----------•-----------•
        | (?-is)^.*XXX.*                  ( TRIVIAL case )     |     NO    |    YES   |      NO   |
        •------------------------------------------------------•-----------•----------•-----------•
        | (?-is)^(.+\R){N}.*XXX.*                              |    YES    |    YES   |      NO   |
        •------------------------------------------------------•-----------•----------•-----------•
        | (?-is)^.*XXX.*\R(.+\R){M}                            |     NO    |    YES   |     YES   |
        •------------------------------------------------------•-----------•----------•-----------•
        | (?-is)^(.+\R){N}.*XXX.*\R(.+\R){M}                   |    YES    |    YES   |     YES   |
        | (?-is)^(.+\R){N}.*XXX.*\R(?1){M}                     |           |          |           |
        •======================================================•===========•==========•===========•
    

    IMPORTANT :

    Of course, you must replace the N and M variables, in the regexes, with an non-null integer, standing for the number of wanted lines, respectively, before and after the specific line X !


    In this second table, here are the regexes which does NOT bookmark any Line X, but only the 1 or 2 lines around the Line X :

        •=========================================================•==========•==========•==========•==========•==========•
        |  REGULAR expression, marking ONE or TWO lines, BEFORE   | 2nd line | 1st line |  Line X  | 1st line | 2nd line |
        |  / AFTER a line X, containing 'XXX', except the line X  |  BEFORE  |  BEFORE  |          |   AFTER  |   AFTER  |
        •=========================================================•==========•==========•==========•==========•==========•
        | (?-is)^.*XXX.*\R.+\R\K.+                                |     NO   |     NO   |     NO   |     NO   |    YES   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.*XXX.*\R\K.+                                    |     NO   |     NO   |     NO   |    YES   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.*XXX.*\R\K.+\R.+                                |     NO   |     NO   |     NO   |    YES   |    YES   |
        •=========================================================•==========•==========•==========•==========•==========•
        | (?-is)^.+(?=\R.*XXX)                                    |     NO   |    YES   |     NO   |     NO   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.+(?=\R.*XXX)|^.*XXX.*\R.+\R\K.+                 |     NO   |    YES   |     NO   |     NO   |    YES   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.+(?=\R.*XXX)|^.*XXX.*\R\K.+                     |     NO   |    YES   |     NO   |    YES   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.+(?=\R.*XXX)|^.*XXX.*\R\K.+\R.+                 |     NO   |    YES   |     NO   |    YES   |    YES   |
        •=========================================================•==========•==========•==========•==========•==========•
        | (?-is)^.+(?=\R.+\R.*XXX)                                |    YES   |     NO   |     NO   |     NO   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.+(?=\R.+\R.*XXX)|^.*XXX.*\R.+\R\K.+             |    YES   |     NO   |     NO   |     NO   |    YES   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.+(?=\R.+\R.*XXX)|^.*XXX.*\R\K.+                 |    YES   |     NO   |     NO   |    YES   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.+(?=\R.+\R.*XXX)|^.*XXX.*\R\K.+\R.+             |    YES   |     NO   |     NO   |    YES   |    YES   |
        •=========================================================•==========•==========•==========•==========•==========•
        | (?-is)^.+\R.+(?=\R.*XXX)                                |    YES   |    YES   |     NO   |     NO   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.+\R.+(?=\R.*XXX)|^.*XXX.*\R.+\R\K.+             |    YES   |    YES   |     NO   |     NO   |    YES   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.+\R.+(?=\R.*XXX)|^.*XXX.*\R\K.+                 |    YES   |    YES   |     NO   |    YES   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.+\R.+(?=\R.*XXX)|^.*XXX.*\R\K.+\R.+             |    YES   |    YES   |     NO   |    YES   |    YES   |
        •=========================================================•==========•==========•==========•==========•==========•
    

    • In the third table, here are the regexes which do bookmark the Line X, as well as 1 or 2 lines around Line X :
        •=========================================================•==========•==========•==========•==========•==========•
        |  REGULAR expression, marking line X, containing 'XXX',  | 2nd line | 1st line |  Line X  | 1st line | 2nd line |
        |   as well as ONE or TWO lines, BEFORE / AFTER line X    |  BEFORE  |  BEFORE  |          |   AFTER  |   AFTER  |
        •=========================================================•==========•==========•==========•==========•==========•
        |  (?-is)^.*XXX.*                    ( Trivial case )     |     NO   |     NO   |    YES   |     NO   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        |  (?-is)^.*XXX.*\R|\G.+\R\K.+                            |     NO   |     NO   |    YES   |     NO   |    YES   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        |  (?-is)^.*XXX.*\R.+                                     |     NO   |     NO   |    YES   |    YES   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        |  (?-is)^.*XXX.*\R.+\R.+                                 |     NO   |     NO   |    YES   |    YES   |    YES   |
        •=========================================================•==========•==========•==========•==========•==========•
        |  (?-is)^.+\R.*XXX.*                                     |     NO   |    YES   |    YES   |     NO   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        |  (?-is)^.+\R.*XXX.*\R|\G.+\R\K.+                        |     NO   |    YES   |    YES   |     NO   |    YES   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        |  (?-is)^.+\R.*XXX.*\R.+                                 |     NO   |    YES   |    YES   |    YES   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        |  (?-is)^.+\R.*XXX.*\R.+\R.+                             |     NO   |    YES   |    YES   |    YES   |    YES   |
        •=========================================================•==========•==========•==========•==========•==========•
        |  (?-is)^.+(?=\R.+\R.*XXX)|^.*XXX.*                      |    YES   |     NO   |    YES   |     NO   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        |  (?-is)^.+(?=\R.+\R.*XXX)|^.*XXX.*\R|\G.+\R\K.+         |    YES   |     NO   |    YES   |     NO   |    YES   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        |  (?-is)^.+(?=\R.+\R.*XXX)|^.*XXX.*\R.+                  |    YES   |     NO   |    YES   |    YES   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        |  (?-is)^.+(?=\R.+\R.*XXX)|^.*XXX.*\R.+\R.+              |    YES   |     NO   |    YES   |    YES   |    YES   |
        •=========================================================•==========•==========•==========•==========•==========•
        |  (?-is)^.+\R.+\R.*XXX.*                                 |    YES   |    YES   |    YES   |     NO   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        |  (?-is)^.+\R.+\R.*XXX.*\R|\G.+\R\K.+                    |    YES   |    YES   |    YES   |     NO   |    YES   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        |  (?-is)^.+\R.+\R.*XXX.*\R.+                             |    YES   |    YES   |    YES   |    YES   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        |  (?-is)^.+\R.+\R.*XXX.*\R.+\R.+                         |    YES   |    YES   |    YES   |    YES   |    YES   |
        •=========================================================•==========•==========•==========•==========•==========•
    

    Although, the different regexes still seem rather difficult to interpret, there are more simple than before ;-))

    Best Regards

    guy038



  • @guy038 said

    …and the commit… https://github.com/alberto-dev/notepad-plus-plus/commit/...

    I think here is the REAL commit into Notepad++ master source for this: https://github.com/notepad-plus-plus/notepad-plus-plus/commit/132441867e48240153e3b84c6e2b213ba3e0655e

    I’m not sure who “alberto” is…



  • @guy038 said

    We are, from now on, able to mark any non-empty line, involved in a multi-lines search ;-))

    Why is the qualifier “non-empty” used here? I can make it mark empty lines as well; example:

    440b1625-77c4-4af8-9701-a5522812b35f-image.png



  • Hi @alan-kilborn and All,

    Good point, Alan ! Indeed, your example works fine, too, on my configuration ;-)) It’s a chance that I wanted to be specific, mentioning “not empty” lines ! Luckily, I understood what happens :

    Consider the simple regex (?-is).*, against any text containing several pure empty lines, only. Obviously, the regex matches a zero length empty string, in any empty line. And, if your try to mark and bookmark these lines nothing is displayed on screen !

    Now, slightly change the regex as (?-is).*\R, against this multi-lines empty text. This time, the regex does match any EOF characters. So, if you use the Mark feature, with the Bookmark line option ticked, all these empty lines are normally bookmarked, and, if you click on the Show All Characters button, of the toolbar, the CR and/or LF control characters, of each pure blank line, are well highlighted in red, as expected !

    In some of my regexes, in order to shorten them, I did not end them with the \R syntax. Thus, this made me think, wrongly, that using the star quantifier *, instead of the plus quantifier + was useless, anyway and that empty lines could not be bookmarked :-((

    But it is not ! So, thanks to you, Alan, I’m going to reexamine all the regexes, described in my previous post, changing, as much as possible, any + quantifier with a * quantifier and adding the \R syntax.

    See you later,

    Best Regards,

    guy038



  • Hi, All,

    So I’ve updated all my previous regexes, in order to bookmark pure empty lines, as well ! ( They do not contain the + quantifier, anymore ! )


    This first table, below, shows how to mark consecutive lines, around a line containing a specific expression XXX. Almost obvious ;-))

        •===•======================================================•===========•==========•===========•
        |   |  REGULAR expression to mark Line X, containing 'XXX' | Nth lines |  Line X  | Mth lines |
        |   |  and Nth lines BEFORE and/or Mth lines AFTER line X  |   BEFORE  |          |   AFTER   |
        •===•======================================================•===========•==========•===========•
        |   | (?-is)^(.*\R){N}(?=.*XXX)                            |    YES    |     NO   |      NO   |
        •---•------------------------------------------------------•-----------•----------•-----------•
        |   | (?-is)^.*XXX.*\R\K(.*\R){M}                          |     NO    |     NO   |     YES   |
        •---•------------------------------------------------------•-----------•----------•-----------•
        | X | (?-is)^(.*\R){N}(?=.*XXX)|.*XXX.*\R\K(.*\R){M}       |    YES    |     NO   |     YES   |
        •---•------------------------------------------------------•-----------•----------•-----------•
        |   | (?-is)^.*XXX.*                    ( TRIVIAL case )   |     NO    |    YES   |      NO   |
        •---•------------------------------------------------------•-----------•----------•-----------•
        |   | (?-is)^(.*\R){N}.*XXX.*                              |    YES    |    YES   |      NO   |
        •---•------------------------------------------------------•-----------•----------•-----------•
        |   | (?-is)^.*XXX.*\R(.*\R){M}                            |     NO    |    YES   |     YES   |
        •---•------------------------------------------------------•-----------•----------•-----------•
        | Y | (?-is)^(.*\R){N}.*XXX.*\R(.*\R){M}                   |    YES    |    YES   |     YES   |
        •===•======================================================•===========•==========•===========•
    

    Notes :

    • You must replace the N and M variables, in the regexes, with an integer, standing for the number of wanted lines, respectively, before and after the specific line X !

    • If you choose N = 0 and/or M = 0, the different regexes still work ! So, with the help of the regexes identified with an, X or Y you can, as well, solve all the described cases ;-))

    • However, if you choose N = 0 and M <> 0, the regex, identified with an X, will not work properly when a criterion XXX begins a line


    In this second table, here are the regexes which does NOT bookmark any Line X, but only the 1 or 2 lines around the Line X :

        •=========================================================•==========•==========•==========•==========•==========•
        |  REGULAR expression, marking ONE or TWO lines, BEFORE   | 2nd line | 1st line |  Line X  | 1st line | 2nd line |
        |  / AFTER a line X, containing 'XXX', except the line X  |  BEFORE  |  BEFORE  |          |   AFTER  |   AFTER  |
        •=========================================================•==========•==========•==========•==========•==========•
        | (?-is)^.*XXX.*\R.*\R\K.*\R                              |     NO   |     NO   |     NO   |     NO   |    YES   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.*XXX.*\R\K.*\R                                  |     NO   |     NO   |     NO   |    YES   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.*XXX.*\R\K.*\R.*\R                              |     NO   |     NO   |     NO   |    YES   |    YES   |
        •=========================================================•==========•==========•==========•==========•==========•
        | (?-is)^.*\R(?=.*XXX)                                    |     NO   |    YES   |     NO   |     NO   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.*\R(?=.*XXX)|^.*XXX.*\R.*\R\K.*\R               |     NO   |    YES   |     NO   |     NO   |    YES   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.*\R(?=.*XXX)|^.*XXX.*\R\K.*\R                   |     NO   |    YES   |     NO   |    YES   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.*\R(?=.*XXX)|^.*XXX.*\R\K.*\R.*\R               |     NO   |    YES   |     NO   |    YES   |    YES   |
        •=========================================================•==========•==========•==========•==========•==========•
        | (?-is)^.*\R(?=.*\R.*XXX)                                |    YES   |     NO   |     NO   |     NO   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.*\R(?=.*\R.*XXX)|^.*XXX.*\R.*\R\K.*\R           |    YES   |     NO   |     NO   |     NO   |    YES   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.*\R(?=.*\R.*XXX)|^.*XXX.*\R\K.*\R               |    YES   |     NO   |     NO   |    YES   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.*\R(?=.*\R.*XXX)|^.*XXX.*\R\K.*\R.*\R           |    YES   |     NO   |     NO   |    YES   |    YES   |
        •=========================================================•==========•==========•==========•==========•==========•
        | (?-is)^.*\R.*\R(?=.*XXX)                                |    YES   |    YES   |     NO   |     NO   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.*\R.*\R(?=.*XXX)|^.*XXX.*\R.*\R\K.*\R           |    YES   |    YES   |     NO   |     NO   |    YES   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.*\R.*\R(?=.*XXX)|^.*XXX.*\R\K.*\R               |    YES   |    YES   |     NO   |    YES   |     NO   |
        •---------------------------------------------------------•----------•----------•----------•----------•----------•
        | (?-is)^.*\R.*\R(?=.*XXX)|^.*XXX.*\R\K.*\R.*\R           |    YES   |    YES   |     NO   |    YES   |    YES   |
        •=========================================================•==========•==========•==========•==========•==========•
    

    • In the third table, here are the regexes which do bookmark the Line X, as well as 1 or 2 lines around Line X :
        •===•===========================================================•==========•==========•==========•==========•==========•
        |   |  REGULAR expression, marking line X, containing 'XXX',    | 2nd line | 1st line |  Line X  | 1st line | 2nd line |
        |   |   as well as ONE or TWO lines, BEFORE / AFTER line X      |  BEFORE  |  BEFORE  |          |   AFTER  |   AFTER  |
        •===•===========================================================•==========•==========•==========•==========•==========•
        |   |  (?-is)^.*XXX.*                        ( Trivial case )   |     NO   |     NO   |    YES   |     NO   |     NO   |
        •---•-----------------------------------------------------------•----------•----------•----------•----------•----------•
        | X |  (?-is)^.*(?=XXX)|\GXXX.*\R.*\R\K.*\R                     |     NO   |     NO   |    YES   |     NO   |    YES   |
        •---•-----------------------------------------------------------•----------•----------•----------•----------•----------•
        |   |  (?-is)^.*XXX.*\R.*\R                                     |     NO   |     NO   |    YES   |    YES   |     NO   |
        •---•-----------------------------------------------------------•----------•----------•----------•----------•----------•
        |   |  (?-is)^.*XXX.*\R.*\R.*\R                                 |     NO   |     NO   |    YES   |    YES   |    YES   |
        •===•===========================================================•==========•==========•==========•==========•==========•
        |   |  (?-is)^.*\R.*XXX.*                                       |     NO   |    YES   |    YES   |     NO   |     NO   |
        •---•-----------------------------------------------------------•----------•----------•----------•----------•----------•
        | X |  (?-is)^.*\R.*(?=XXX)|\GXXX.*\R.*\R\K.*\R                 |     NO   |    YES   |    YES   |     NO   |    YES   |
        •---•-----------------------------------------------------------•----------•----------•----------•----------•----------•
        |   |  (?-is)^.*\R.*XXX.*\R.*\R                                 |     NO   |    YES   |    YES   |    YES   |     NO   |
        •---•-----------------------------------------------------------•----------•----------•----------•----------•----------•
        |   |  (?-is)^.*\R.*XXX.*\R.*\R.*\R                             |     NO   |    YES   |    YES   |    YES   |    YES   |
        •===•===========================================================•==========•==========•==========•==========•==========•
        |   |  (?-is)^.*\R(?=.*\R.*XXX)|^.*XXX.*                        |    YES   |     NO   |    YES   |     NO   |     NO   |
        •---•-----------------------------------------------------------•----------•----------•----------•----------•----------•
        | X |  (?-is)^.*\R(?=.*\R.*XXX)|^.*(?=XXX)|\GXXX.*\R.*\R\K.*\R  |    YES   |     NO   |    YES   |     NO   |    YES   |
        •---•-----------------------------------------------------------•----------•----------•----------•----------•----------•
        |   |  (?-is)^.*\R(?=.*\R.*XXX)|^.*XXX.*\R.*\R                  |    YES   |     NO   |    YES   |    YES   |     NO   |
        •---•-----------------------------------------------------------•----------•----------•----------•----------•----------•
        |   |  (?-is)^.*\R(?=.*\R.*XXX)|^.*XXX.*\R.*\R.*\R              |    YES   |     NO   |    YES   |    YES   |    YES   |
        •===•===========================================================•==========•==========•==========•==========•==========•
        |   |  (?-is)^.*\R.*\R.*XXX.*                                   |    YES   |    YES   |    YES   |     NO   |     NO   |
        •---•-----------------------------------------------------------•----------•----------•----------•----------•----------•
        | X |  (?-is)^.*\R.*\R.*(?=XXX)|\GXXX.*\R.*\R\K.*\R             |    YES   |    YES   |    YES   |     NO   |    YES   |
        •---•-----------------------------------------------------------•----------•----------•----------•----------•----------•
        |   |  (?-is)^.*\R.*\R.*XXX.*\R.*\R                             |    YES   |    YES   |    YES   |    YES   |     NO   |
        •---•-----------------------------------------------------------•----------•----------•----------•----------•----------•
        |   |  (?-is)^.*\R.*\R.*XXX.*\R.*\R.*\R                         |    YES   |    YES   |    YES   |    YES   |    YES   |
        •===•===========================================================•==========•==========•==========•==========•==========•
    

    Notes :

    • Due to the \G syntax, in the 4 regexes, identified with an X, results are not correct when a criterion XXX begins a line

    • When these regexes are used and that the criterion XXX, does not begin a line, as a side-effect, the only characters, before XXX, will be red-marked. But, luckily, any line, containing XXX, will be correctly bookmarked :-))

    Best Regards,

    guy038



  • @guy038 said:

    …the regex matches a zero length empty string, in any empty line. And, if your try to mark and bookmark these lines nothing is displayed on screen !

    Yes, I suppose that one needs to keep in mind that if a (successful) operation results in no marked text (such as a zero-length match) then as a consequence there is not going to be any bookmarked line either.


Log in to reply