简体   繁体   中英

REGEX PCRE Recursive expression for nested text matching

So i am trying to do something like this (yes, including newlines):

Match #1

START
    START
        stuff
    STOP
    more stuff
STOP

Match #2

START
    START
        stuff
    STOP
    more stuff
STOP

This is how far i have come

START(.*?^(?:(?!STOP).)*$|(?R))|STOP with the parameters "g" "m" "i" and "s"

The problem is that i cannot match anything after the STOP wihtout matching the last "STOP" in the entire text.

Here is a regex101 example

https://regex101.com/r/vD4nX6/1

I would appriciate some guidance

Thanks in advance

Here's a pattern that matches your example:

^\h*START\h*\n(?:\h*+(?!(?:START|STOP)\h*$)[^\n]*\n|(?R)\n)*\h*STOP\h*$

using the /mg flags (live at https://regex101.com/r/iK9tK5/1 ).

The idea behind it:

^                                  # beginning of line
\h* START \h* \n                   # "START" optionally surrounded by horizontal whitespace
                                   #   on a line of its own
(?:                                # between START/STOP, every line is either "normal"
                                   #   or a recursive START/STOP block
    \h*+                           # a normal line starts with optional horizontal whitespace
    (?!                            #   ... not followed by ...
        (?: START | STOP ) \h* $   #   "START" or "STOP" on their own
    )
    [^\n]* \n                      # any characters, then a newline
|
    (?R) \n                        # otherwise it's a recursive START/STOP block
)*                                 # we can have as many items as we want between START/STOP
\h* STOP \h*                       # "STOP" optionally surrounded by horizontal whitespace
$                                  # end of line

I've made \\h*+ possessive in order to avoid accidentally matching " STOP" by 0 iterations of \\h* , not followed by "STOP" (they're followed by " STOP" (with a space)). The + forces \\h to match as many times as it possibly can, so it has to consume the space.

Alternatively you could pull \\h* into the look-ahead: (?!\\h*(?:START|STOP)\\h*$)
That would also work, but then the look-ahead would skip over any spaces to see whether they're followed by START/STOP, only to have [^\\n]* outside go over those same spaces again. With \\h*+ at the start, we match those spaces once, with no backtracking. I guess it's a micro-optimization.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM